Crash on launch involving a branch table, weak bindings, and no-pic

Originator:ryan.brown
Number:rdar://27696860 Date Originated:2016-08-04
Status:Open Resolved:
Product:Developer Tools Product Version:Xcode 5.0 (possibly before) - Xcode 8.0
Classification: Reproducible:Always
 
Summary:

Minimal test case:
https://gist.github.com/ryb-ableton/7720a07dd58a9c9a683c5778ccf4c5e3

Real-world test case using Boost.Regex:
https://gist.github.com/ryb-ableton/01ec990172284cf4471ec4d7a13cec48

The bug involves:
- Compiling for i386.
- Using -mdynamic-no-pic and -Wl,-read_only_relocs,suppress to build a dylib.
- A template member function with a switch statement that generates a branch table.
- Taking the address of the function from multiple locations (e.g two dylibs or a dylib and the executable).

The crash happens because dyld writes to memory from the read-only __TEXT segment while binding weak symbols. The weak bindings here make the member function's address consistent everywhere. dyld doesn't make the __TEXT segment writable prior to making weak bindings (in ImageLoader::weakBind()), unlike for rebasing (ImageLoaderMachO::doRebase()).

Steps to Reproduce:
1- Download the minimal test case above
2- Run `make && make check`

To build the Boost test case you need to download Boost – see the commands in the Makefile.

Expected Results:
No crash.

Actual Results:
Crash while launching the test executable:

 + 293, stop reason = EXC_BAD_ACCESS (code=2, address=0x3f7a)
  * frame #0: 0x8fe139bf dyld`ImageLoaderMachO::bindLocation(ImageLoader::LinkContext const&, unsigned long, unsigned long, ImageLoader const*, unsigned char, char const*, long, char const*) + 293
    frame #1: 0x8fe1cd5e dyld`ImageLoaderMachOCompressed::updateUsesCoalIterator(ImageLoader::CoalIterator&, unsigned long, ImageLoader*, ImageLoader::LinkContext const&) + 478
    frame #2: 0x8fe0fb99 dyld`ImageLoader::weakBind(ImageLoader::LinkContext const&) + 1011
    frame #3: 0x8fe05c37 dyld`dyld::_main(macho_header const*, unsigned long, int, char const**, char const**, char const**, unsigned long*) + 3498
    frame #4: 0x8fe01231 dyld`dyldbootstrap::start(macho_header const*, int, char const**, long, macho_header const*, unsigned long*) + 427
    frame #5: 0x8fe01047 dyld`_dyld_start + 71

Version:
Xcode 5.0 (possibly before) - Xcode 8.0

Notes:
The crash does not occur if jump tables are suppressed using -fno-jump-tables. This option is available on llvm HEAD, but is not yet in Apple's clang.

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!