gcc icon indicating copy to clipboard operation
gcc copied to clipboard

libstdc++ must use thread-local errno

Open jclulow opened this issue 4 years ago • 2 comments

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.

jclulow avatar May 28 '21 01:05 jclulow

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>

jclulow avatar May 28 '21 17:05 jclulow