Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exceptions constructed from std::string bypass catch handlers on Clang 18 #94292

Open
alexanderchuranov opened this issue Jun 3, 2024 · 5 comments

Comments

@alexanderchuranov
Copy link

Exceptions constructed from an std::string bypass catch handlers and terminate the program. The same exception constructed from a string literal behaves normally. The following program compiled with Clang 14 catches both exceptions. However, on Clang 18 the "dynamic" version terminates the program with the following message:

libc++abi: terminating due to uncaught exception of type std::runtime_error: dynamic

// clang++ -std=c++20
#include <iostream>
#include <stdexcept>
#include <string>

void literal() {
  throw std::runtime_error("literal");
}

void dynamic() {
  throw std::runtime_error(std::string("dynamic"));
}

int main() {
  for (auto f : {literal, dynamic}) {
    try {
      f();
    } catch (std::runtime_error e) {
      std::cerr << "caught: " << e.what() << std::endl;
    }
  }
}

Working compiler:

  • Apple clang version 14.0.3 (clang-1403.0.22.14.1)
  • Target: arm64-apple-darwin22.5.0
  • Thread model: posix

Compiler that fails:

  • Homebrew clang version 18.1.6
  • Target: arm64-apple-darwin22.5.0
  • Thread model: posix
@github-actions github-actions bot added the clang Clang issues not falling into any other category label Jun 3, 2024
@EugeneZelenko EugeneZelenko added libunwind and removed clang Clang issues not falling into any other category labels Jun 3, 2024
@DimitryAndric
Copy link
Collaborator

Don't see it here, on macOS 13.6.7 (M1):

% uname -a
Darwin macbookair 22.6.0 Darwin Kernel Version 22.6.0: Mon Apr 22 20:50:39 PDT 2024; root:xnu-8796.141.3.705.2~1/RELEASE_ARM64_T8103 arm64

% /usr/bin/clang++ -v
Apple clang version 15.0.0 (clang-1500.1.0.2.5)
Target: arm64-apple-darwin22.6.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

% /usr/bin/clang++ -std=c++20 pr94292.cpp -o pr94292

% ./pr94292
caught: literal
caught: dynamic

% /opt/homebrew/opt/llvm/bin/clang++ -v
Homebrew clang version 18.1.6
Target: arm64-apple-darwin22.6.0
Thread model: posix
InstalledDir: /opt/homebrew/opt/llvm/bin
% /opt/homebrew/opt/llvm/bin/clang++ -std=c++20 pr94292.cpp -o pr94292

% ./pr94292
caught: literal
caught: dynamic

@alexanderchuranov
Copy link
Author

Thank you for looking into this!

I see now that the problem depends on the compiler flags.

> /opt/homebrew/opt/llvm/bin/clang++ -v
Homebrew clang version 18.1.6
Target: arm64-apple-darwin22.5.0
Thread model: posix
InstalledDir: /opt/homebrew/opt/llvm/bin

> /opt/homebrew/opt/llvm/bin/clang++ \ 
  -std=c++20 \
  -I/opt/homebrew/opt/llvm/include \
  -L/opt/homebrew/opt/llvm/lib/c++ \
  -o pr94292 pr94292.cpp
ld: warning: dylib (/opt/homebrew/opt/llvm/lib/c++/libc++.dylib) was built for newer macOS version (13.6) than being linked (13.0)

> ./pr94292 
caught: literal
libc++abi: terminating due to uncaught exception of type std::runtime_error: dynamic

The problem does not reproduce when I remove the -L/opt/homebrew/opt/llvm/lib/c++:

> /opt/homebrew/opt/llvm/bin/clang++ \
  -std=c++20 \
  -I/opt/homebrew/opt/llvm/include \
  -o pr94292 pr94292.cpp

> ./pr94292 
caught: literal
caught: dynamic

This is still surprising, because brew llvm info suggests these environment variables:

export LDFLAGS="-L/opt/homebrew/opt/llvm/lib"
export CPPFLAGS="-I/opt/homebrew/opt/llvm/include"
LDFLAGS="-L/opt/homebrew/opt/llvm/lib/c++ -Wl,-rpath,/opt/homebrew/opt/llvm/lib/c++"

The compilation works when I'm running it with all those variables set.

> echo ${LDFLAGS}

> echo ${CPPFLAGS}

> export LDFLAGS="-L/opt/homebrew/opt/llvm/lib"
> export CPPFLAGS="-I/opt/homebrew/opt/llvm/include"
> LDFLAGS="-L/opt/homebrew/opt/llvm/lib/c++ -Wl,-rpath,/opt/homebrew/opt/llvm/lib/c++"
> /opt/homebrew/opt/llvm/bin/clang++ \
  -std=c++20 \
  -o pr94292 pr94292.cpp

> ./pr94292 
caught: literal
caught: dynamic

But it doesn't work if all the same values are specified directly on the command-line:

> /opt/homebrew/opt/llvm/bin/clang++ \
  -std=c++20 \
  -I/opt/homebrew/opt/llvm/include \  
  -L/opt/homebrew/opt/llvm/lib \
  -L/opt/homebrew/opt/llvm/lib/c++ -Wl,-rpath,/opt/homebrew/opt/llvm/lib/c++ \
  -o pr94292 pr94292.cpp
ld: warning: dylib (/opt/homebrew/opt/llvm/lib/c++/libc++.dylib) was built for newer macOS version (13.6) than being linked (13.0)
ld: warning: dylib (/opt/homebrew/opt/llvm/lib/libunwind.dylib) was built for newer macOS version (13.6) than being linked (13.0)
ld: warning: dylib (/opt/homebrew/opt/llvm/lib/libunwind.dylib) was built for newer macOS version (13.6) than being linked (13.0)

> ./pr94292 
caught: literal
libc++abi: terminating due to uncaught exception of type std::runtime_error: dynamic

@alexanderchuranov
Copy link
Author

BTW the culprit is the flag -L/opt/homebrew/opt/llvm/lib/c++.

> /opt/homebrew/opt/llvm/bin/clang++ \
  -std=c++20 \
  -I/opt/homebrew/opt/llvm/include \
  -L/opt/homebrew/opt/llvm/lib \
  -L/opt/homebrew/opt/llvm/lib/c++ \
  -o pr94292 pr94292.cpp
ld: warning: dylib (/opt/homebrew/opt/llvm/lib/c++/libc++.dylib) was built for newer macOS version (13.6) than being linked (13.0)
ld: warning: dylib (/opt/homebrew/opt/llvm/lib/libunwind.dylib) was built for newer macOS version (13.6) than being linked (13.0)
ld: warning: dylib (/opt/homebrew/opt/llvm/lib/libunwind.dylib) was built for newer macOS version (13.6) than being linked (13.0)

> ./pr94292 
caught: literal
libc++abi: terminating due to uncaught exception of type std::runtime_error: dynamic

Removing that particular search path fixes the problem:

> /opt/homebrew/opt/llvm/bin/clang++ \
  -std=c++20 \
  -I/opt/homebrew/opt/llvm/include \
  -L/opt/homebrew/opt/llvm/lib \
  -o pr94292 pr94292.cpp
ld: warning: dylib (/opt/homebrew/opt/llvm/lib/libunwind.dylib) was built for newer macOS version (13.6) than being linked (13.0)
ld: warning: dylib (/opt/homebrew/opt/llvm/lib/libunwind.dylib) was built for newer macOS version (13.6) than being linked (13.0)

> ./pr94292 
caught: literal
caught: dynamic

@alexanderchuranov
Copy link
Author

I don't know now if this is still a bug in LLVM or it is my ignorance about the proper ways to pass flag values from the compiler front-end to the linker.

It would still be nice to understand why this happens, but it's not a critical problem.

Thanks!

@det
Copy link

det commented Jun 19, 2024

I see this problem, too. It only happens when using libc++.1.dylib from LLVM 18.1.X. Removing the -L flag makes it use the system libc++abi.1.dylib.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants