forked from OSchip/llvm-project
[tsan] Fix "failed to intercept sysctlnametomib" on FreeBSD
The sysctlnametomib function is called from __tsan::Initialize via __sanitizer::internal_sysctlbyname (see stack trace below). This results in a fatal error since sysctlnametomib has not been intercepted yet. This patch allows internal_sysctlbyname to be called before __tsan::Initialize() has completed. On FreeBSD >= 1300045 sysctlbyname() is a real syscall, but for older versions it calls sysctlnametomib() followed by sysctl(). To avoid calling the intercepted version, look up the real sysctlnametomib() followed by internal_sysctl() if the syscall is not available. This reduces check-sanitizer failures from 62 to 11 for me. ==34433==FATAL: ThreadSanitizer: failed to intercept sysctlnametomib at /exports/users/alr48/sources/upstream-llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_termination.cpp:51 name=0x7fffffffce10, namelenp=0x7fffffffce08) at /exports/users/alr48/sources/upstream-llvm-project/compiler-rt/lib/tsan/../sanitizer_common/sanitizer_common_interceptors.inc:7908 oldp=0x7fffffffcf2c, oldlenp=0x7fffffffcf20, newp=0x0, newlen=0) at /exports/users/alr48/sources/upstream-llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp:803 at /exports/users/alr48/sources/upstream-llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp:2152 at /exports/users/alr48/sources/upstream-llvm-project/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp:367 fname=0x21c731 "readlink", pc=34366042556) at /exports/users/alr48/sources/upstream-llvm-project/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp:255 bufsiz=1024) at /exports/users/alr48/sources/upstream-llvm-project/compiler-rt/lib/tsan/../sanitizer_common/sanitizer_common_interceptors.inc:7151 Reviewed By: #sanitizers, vitalybuka Differential Revision: https://reviews.llvm.org/D85292
This commit is contained in:
parent
32a8a10b42
commit
7be8682921
|
@ -800,11 +800,29 @@ int internal_sysctl(const int *name, unsigned int namelen, void *oldp,
|
|||
#if SANITIZER_FREEBSD
|
||||
int internal_sysctlbyname(const char *sname, void *oldp, uptr *oldlenp,
|
||||
const void *newp, uptr newlen) {
|
||||
static decltype(sysctlbyname) *real = nullptr;
|
||||
if (!real)
|
||||
real = (decltype(sysctlbyname) *)dlsym(RTLD_NEXT, "sysctlbyname");
|
||||
CHECK(real);
|
||||
return real(sname, oldp, (size_t *)oldlenp, newp, (size_t)newlen);
|
||||
// Note: this function can be called during startup, so we need to avoid
|
||||
// calling any interceptable functions. On FreeBSD >= 1300045 sysctlbyname()
|
||||
// is a real syscall, but for older versions it calls sysctlnametomib()
|
||||
// followed by sysctl(). To avoid calling the intercepted version and
|
||||
// asserting if this happens during startup, call the real sysctlnametomib()
|
||||
// followed by internal_sysctl() if the syscall is not available.
|
||||
#ifdef SYS___sysctlbyname
|
||||
return internal_syscall(SYSCALL(__sysctlbyname), sname,
|
||||
internal_strlen(sname), oldp, (size_t *)oldlenp, newp,
|
||||
(size_t)newlen);
|
||||
#else
|
||||
static decltype(sysctlnametomib) *real_sysctlnametomib = nullptr;
|
||||
if (!real_sysctlnametomib)
|
||||
real_sysctlnametomib =
|
||||
(decltype(sysctlnametomib) *)dlsym(RTLD_NEXT, "sysctlnametomib");
|
||||
CHECK(real_sysctlnametomib);
|
||||
|
||||
int oid[CTL_MAXNAME];
|
||||
size_t len = CTL_MAXNAME;
|
||||
if (real_sysctlnametomib(sname, oid, &len) == -1)
|
||||
return (-1);
|
||||
return internal_sysctl(oid, len, oldp, oldlenp, newp, newlen);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue