libstdc++ must use thread-local errno
It would seem that libstdc++.so.0.6.28 does not end up built with -D_TS_ERRNO defined (e.g., via -D_REENTRANT). This results in errno checks in, for example, std::filesystem::status() looking at the global errno rather than using *___errno() as it should to local the thread-specific error number.
This was noticed when trying to use Clickhouse, a large C++ program that makes heavy use of threads. The std::filesystem::exists() call would throw unexpectedly for files or directories that did not exist -- but it would report "Error 0" as the reason.
It's possible to pass -D_TS_ERRNO in via CFLAGS and CXXFLAGS while building GCC -- but I expect we should enable this by default and always in the source itself, in order to ensure correct binaries are always created.
Looking a bit closer to demonstrate the use of the errno global, first in the source:
https://github.com/illumos/gcc/blob/aa6086b73844ed5d9bb62e249c15bad87ce0e0a0/libstdc%2B%2B-v3/src/c%2B%2B17/fs_ops.cc#L1479-L1483
And then in the disassembly on an OmniOS r151038c machine:
$ mdb -e '$G; _ZNSt10filesystem6statusERKNS_7__cxx114pathERSt10error_code+0x26::dis -n 3' \
/usr/gcc/10/lib/amd64/libstdc++.so.6.0.28
C++ symbol demangling enabled
std::filesystem::status+0x1d: call -0xd1a7a <PLT:stat>
std::filesystem::status+0x22: testl %eax,%eax
std::filesystem::status+0x24: je +0x5a <std::filesystem::status+0x80>
std::filesystem::status+0x26: movq +0x5796b(%rip),%rax <0x22c658>
std::filesystem::status+0x2d: movl $0xffff,%r13d
std::filesystem::status+0x33: movl (%rax),%ebx
std::filesystem::status+0x35: call -0xd5112 <PLT:_ZNSt3_V216generic_categoryEv>
Note that after the call to stat() we move a value through a relocated pointer (0x22c658):
$ elfdump /usr/gcc/10/lib/amd64/libstdc++.so.6.0.28 | grep 0x22c658
R_AMD64_GLOB_DATA 0x22c658 0 .SUNW_reloc errno
On a machine where we passed -D_TS_ERRNO during the build of GCC 10, we instead see a call to ___errno() as expected:
$ mdb -e '$G; _ZNSt10filesystem6statusERKNS_7__cxx114pathERSt10error_code+0x26::dis -n 3' \
/usr/gcc/10/lib/amd64/libstdc++.so.6.0.28
C++ symbol demangling enabled
std::filesystem::status+0x1d: call -0xd19aa <PLT:stat>
std::filesystem::status+0x22: testl %eax,%eax
std::filesystem::status+0x24: je +0x5a <std::filesystem::status+0x80>
std::filesystem::status+0x26: call -0xd3cf3 <PLT:___errno>
std::filesystem::status+0x2b: movl $0xffff,%r12d
std::filesystem::status+0x31: movl (%rax),%ebx
std::filesystem::status+0x33: call -0xd5040 <PLT:_ZNSt3_V216generic_categoryEv>
See also: 13842 thread-local errno is all you need