Skip to content

Exceptions from std::async cannot be caught on macOS ARM with Clang 18+ #168287

@ruoka

Description

@ruoka

Exceptions from std::async cannot be caught on macOS ARM with Clang 18+

Summary

On macOS ARM with Clang 18+, exceptions thrown from std::async contexts cannot be caught properly. The exception escapes all catch blocks and causes program termination with libc++abi: terminating due to uncaught exception.

Important Finding: This bug is NOT module-specific. It affects both C++ modules and regular C++ code when using std::async.

Environment

  • Platform: macOS ARM (Apple Silicon)
  • Compiler: Clang 18+ (tested with Clang 21.1.5)
  • Standard Library: libc++ (Homebrew LLVM)
  • Optimization: All optimization levels (-O0, -O1, -O2, -O3) - bug occurs regardless

Minimal Reproduction

#include <iostream>
#include <stdexcept>
#include <future>

struct custom_exception : public std::runtime_error {
    custom_exception() : std::runtime_error("custom_exception") {}
};

// Key: The std::async call must be in a separate function to trigger the bug
void throw_from_async() {
    auto future = std::async(std::launch::async, []() {
        throw custom_exception{};
    });
    future.get();
}

int main() {
    try {
        throw_from_async();
    }
    catch (const custom_exception& e) {
        std::cout << "SUCCESS: Exception caught: " << e.what() << "\n";
        return 0;
    }
    catch (...) {
        std::cout << "FAILED: Exception not caught\n";
        return 1;
    }
}

Compile:

clang++ -std=c++20 -stdlib=libc++ -O3 \
  -L/opt/homebrew/opt/llvm/lib/c++ -L/opt/homebrew/opt/llvm/lib \
  -Wl,-rpath,/opt/homebrew/opt/llvm/lib/c++ -Wl,-rpath,/opt/homebrew/opt/llvm/lib \
  -lc++ \
  minimal_repro.cpp -o minimal_repro

Or use the provided build script: minimal_repro.sh

Expected: Exception is caught, prints "SUCCESS: Exception caught"

Actual: Program terminates with:

libc++abi: terminating due to uncaught exception of type custom_exception: custom_exception

Root Cause Analysis

Based on investigation, this appears to be related to:

  1. LLVM built-in unwinder: The bug is specific to macOS ARM where LLVM's built-in unwinder is enabled by default in Homebrew Clang 18+
  2. Exception propagation across threads: The issue manifests specifically with std::async, suggesting problems with exception unwinding across thread boundaries
  3. Function boundaries: The bug requires the std::async call to be in a separate function (not inlined into main())

Additional Context

  • The bug does not occur on Linux ARM (e.g., Asahi Linux) with the same Clang version
  • The bug does not occur with Clang < 18
  • The bug affects both module and non-module code
  • The bug persists even with explicit RTTI flags (-frtti -fexceptions -fcxx-exceptions)
  • The bug occurs at all optimization levels (-O0, -O1, -O2, -O3) - optimization level does not affect the bug

Workaround

No known workaround: The bug occurs at all optimization levels (-O0 through -O3).

The only potential workaround is to avoid using std::async with exceptions on macOS ARM, or to catch exceptions within the async lambda itself before they propagate across thread boundaries.

Related Issues

This may be related to or a duplicate of:

Test Cases

A comprehensive test suite demonstrating the bug is available. The minimal reproduction code is included above, and test files are available as GitHub Gists:

  • Minimal reproduction: minimal_repro.cpp (44 lines, also included above)
  • Build script: minimal_repro.sh - Automated build and test script
  • Full test suite with 11 test cases covering various exception patterns
  • Non-module test confirming bug is not module-specific

Steps to Reproduce

  1. On macOS ARM, install Homebrew LLVM: brew install llvm
  2. Compile the minimal reproduction code above with -O3
  3. Run the executable
  4. Observe program termination instead of exception being caught

Impact

This bug affects any code using std::async with exception handling on macOS ARM, making it impossible to properly handle exceptions from asynchronous operations. This is a critical issue for production code relying on exception safety in concurrent contexts.

Metadata

Metadata

Assignees

No one assigned

    Labels

    c++11clangClang issues not falling into any other categorylibc++libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.platform:macos

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions