Any known issues with libc++ exceptions and cross-thread exception propagation?

Hi everyone. I'm working on getting Intel's Thread Building Blocks
library to compile and run with libc++ on Mac OS X 10.7. I have it
mostly working, but I'm seeing sporadic failures in its test suite
related to the library's exception propagation features. In
particular, exceptions appear occasionally not to get thrown when
expected, and occasionally appear with the wrong type_info. My
attempts at printf debugging however seem to make the problems go away
entirely, so I think there might be threading heisenbugs at fault
here. Before investigating deeper, I wanted to ask first if there are
any known issues with libc++ that would cause problems with passing
exceptions between threads. Is libc++'s exception_ptr implementation
not properly thread safe yet, or are there any other potential
gotchas? TBB currently tries to use the obsolete draft function
"copy_exception" instead of the final standard "make_exception_ptr" to
capture exception objects; are there semantic differences between the
draft and final interfaces that could cause problems?

For reference, here's the current state of the patch against Threading
Building Blocks 4.0 Update 5 I'm working with:

https://gist.github.com/3154264

Thanks for any help!

-Joe

Hi Joe,

The exception_ptr implementation on Lion uses atomics (__sync_add_and_fetch) to manage the reference count underlying exception_ptr, so that copying it should be thread safe. Offhand I can't immediately think of any known issues that would result in the symptoms you're describing.

I was under the impression that make_exception_ptr shipped on Lion and that copy_exception did not. Though I could be mistaken. But there should be no semantic difference between the two.

Howard

Thanks for the reply, Howard. You're right about make_exception_ptr. I
had to alter TBB to use make_exception_ptr because it currently tries
to use copy_exception. I was just making sure that doing so didn't
also change the meaning of the program.

I tracked down a problem in Lion's libc++abi. It appears that
__cxa_rethrow_primary_exception doesn't update the internal
uncaughtExceptions count, which causes it to underflow at the next
catch and thereby causes uncaught_exception to erroneously return true
when there are no exceptions in flight. The following test case
aggravates it:

Wow, awesome debugging job Joe! Sorry about the bug. It has been fixed in the llvm version of libc++abi (http://libcxxabi.llvm.org).

Howard

Good to know, Howard. Is it supported to build and link against static
libc++ and libc++abi libraries newer than the platform's?

-Joe

Nope.

But I do regularly for development purposes. A nice non-intrusive way to do this temporarily is:

$ export DYLD_LIBRARY_PATH=<path>:<path>

$ man dyld
DYLD_LIBRARY_PATH
              This is a colon separated list of directories that contain libraries. The dynamic linker searches these directories
              before it searches the default locations for libraries. It allows you to test new versions of existing libraries.

              For each library that a program uses, the dynamic linker looks for it in each directory in DYLD_LIBRARY_PATH in turn.
              If it still can't find the library, it then searches DYLD_FALLBACK_FRAMEWORK_PATH and DYLD_FALLBACK_LIBRARY_PATH in
              turn.

              Use the -L option to otool(1). to discover the frameworks and shared libraries that the executable is linked
              against.

I point DYLD_LIBRARY_PATH towards my recent libc++abi build in one shell, and not in another, and I can easily run the same executable from either shell and note differences.

Howard

Good to know, Howard. Is it supported to build and link against static
libc++ and libc++abi libraries newer than the platform's?

No. In particular, you should never do the library replacement as
described on http://libcxx.llvm.org/
Otherwise you might end with semi-functional system. For example, for
me everything was more or less ok, but printer driver just crashed.