Repository navigation
Description
Problem Summary
We hit a clang-built binary crash in Apache Doris when using Apache Arrow Flight.
The crash happens inside Apache Arrow's arrow::Status::message() implementation. Arrow 17.0.0 defines an empty OK-status message as a function-local static const std::string inside an inline method in status.h:
const std::string& message() const {
static const std::string no_message = "";
return ok() ? no_message : state_->msg;
}In our clang-built Apache Doris BE binary, the inline static std::string object is emitted as a weak/COMDAT symbol and placed in .data.rel.ro. After relocation, RELRO makes this section read-only. However, C++ function-local static variables are lazily initialized on first execution. The first call to Status::message() tries to construct no_message at runtime, and the std::string constructor writes to the object storage in .data.rel.ro, causing SIGSEGV invalid permissions for mapped object. We suspect this is a clang/lld section placement or COMDAT/RELRO interaction issue: a lazily initialized non-trivial object is placed into a runtime read-only mapping.
$ readelf -sW doris/output/be/lib/doris_be | c++filt | grep 'Status::message.*no_message'
105229: 000000007d6958e0 32 OBJECT WEAK DEFAULT 28 arrow::Status::message[abi:cxx11]() const::no_message[abi:cxx11]
$ readelf -SW doris/output/be/lib/doris_be | grep '\[ *28\]'
[28] .data.rel.ro PROGBITS 000000007d0f7720 7d0f6720 7e4208 00 WA 0 0 32Workaround used in Apache Doris
Related PR: apache/doris#63191
We worked around this in the Doris third-party Arrow patch by avoiding the header-inline function-local static const std::string object and by making non-OK statuses return state_->msg before touching the OK-message sentinel:
const std::string& message() const {
if (state_ != nullptr) {
return state_->msg;
}
return NoMessage();
}Toolchain
Project context:
Apache Doris with Apache Arrow 17.0.0 built as a third-party dependency.
Build mode:
DORIS_TOOLCHAIN=clang
BUILD_TYPE=RELEASE
ENABLE_PCH=false
Toolchain:
clang version 21.1.8
clang++ version 21.1.8
Target: x86_64-pc-linux-gnu
LLD 21.1.8
gcc/g++ runtime toolchain: Gentoo GCC 15.2.0
libstdc++ exports up to GLIBCXX_3.4.34
Linker:
ld is a symlink to ld.lld, which points to lld.
The effective linker is LLD 21.1.8.
Build tools:
CMake 3.29.0
Ninja 1.13.2
ccache 4.5.1
Runtime / OS:
glibc 2.34
Linux 5.14.0-694.el9.x86_64
x86_64 GNU/Linux
Is placing a lazily initialized function-local static const std::string from an inline function into .data.rel.ro expected behavior under clang/lld? If not, should clang or lld ensure that such objects remain in a writable section until their lazy initialization has completed?
Activity
efriedma-quic commentedon May 26, 2026
Not completely sure what's happening without a testcase. But I would guess you're mixing "-std=" flags, so one version of the variable is constexpr-evaluated, and another version isn't, then somehow the two versions get confused during linking.
linrrzqqq commentedon Jul 13, 2026
Thanks for your answer, already fixed by: apache/doris#64390