OpenMethod fails some of the tests on the posix GHA job (bigendian-s390x, yes, clang, 17, ubuntu-22.04, no, fedora, 34, s390x). Claude traces it (convincingly, see below) to a clang 12 bug on all big-endian platforms. Please upgrade to clang 13.
The root cause: a clang ≤ 12 big-endian codegen bug
Ruling out the layers one by one (symbols/exports correct; LD_DEBUG=bindings shows ld.so binding the DSO's fn and guard to the exe correctly), the smoking gun was in the disassembly
of the guard code itself:
asm
llc %r0, 0(%r1) ; CHECK: load byte 0 of the guard
mvghi 0(%r1), 1 ; SET: store 8-byte immediate 1
For non-local guarded variables (template statics take clang's unsynchronized guard path), clang 12 emits the check as load byte 0 but the set as store i64 1. On big-endian, the 0x01
lands in byte 7 — byte 0 stays 0 forever, so every DSO's initializer believes the guard is unset and re-runs the constructor on the correctly-unified object. Debug: second push_back
on the same method_info → your assert. Release: odr_check::inc re-runs → count == 2 → "conflicting definitions" — a false positive, because the detector itself is built on the same
broken primitive. Little-endian is immune (byte 0 of i64 1 is 0x01); gcc is immune (byte store + GNU_UNIQUE).
Confirmed in source: clang 12's ItaniumCXXABI.cpp:2475 does CreateStore(ConstantInt::get(guardTy, 1)); fixed in clang 13 by LLVM commit 6b1e2fc893 ("Manipulate the first byte of
guard variable type in both load and store operation", 2021-02-08) — verified present in release/12.x and gone in 13.x through 18.x.
OpenMethod fails some of the tests on the posix GHA job (bigendian-s390x, yes, clang, 17, ubuntu-22.04, no, fedora, 34, s390x). Claude traces it (convincingly, see below) to a clang 12 bug on all big-endian platforms. Please upgrade to clang 13.