Skip to content

Commit

Permalink
[sanitizer] Define SANITIZER_GLIBC to refine SANITIZER_LINUX feature …
Browse files Browse the repository at this point in the history
…detection and support musl

Several `#if SANITIZER_LINUX && !SANITIZER_ANDROID` guards are replaced
with the more appropriate `#if SANITIZER_GLIBC` (the headers are glibc
extensions, not specific to Linux (i.e. if we ever support GNU/kFreeBSD
or Hurd, the guards may automatically work)).

Several `#if SANITIZER_LINUX && !SANITIZER_ANDROID` guards are refined
with `#if SANITIZER_GLIBC` (the definitions are available on Linux glibc,
but may not be available on other libc (e.g. musl) implementations).

This patch makes `ninja asan cfi msan stats tsan ubsan xray` build on a musl based Linux distribution (apk install musl-libintl)
Notes about disabled interceptors for musl:

* `SANITIZER_INTERCEPT_GLOB`: musl does not implement `GLOB_ALTDIRFUNC` (GNU extension)
* Some ioctl structs and functions operating on them.
* `SANITIZER_INTERCEPT___PRINTF_CHK`: `_FORTIFY_SOURCE` functions are GNU extension
* `SANITIZER_INTERCEPT___STRNDUP`: `dlsym(RTLD_NEXT, "__strndup")` errors so a diagnostic is formed. The diagnostic uses `write` which hasn't been intercepted => SIGSEGV
* `SANITIZER_INTERCEPT_*64`: the `_LARGEFILE64_SOURCE` functions are glibc specific. musl does something like `#define pread64 pread`
* Disabled `msg_iovlen msg_controllen cmsg_len` checks: musl is conforming while many implementations (Linux/FreeBSD/NetBSD/Solaris) are non-conforming. Since we pick the glibc definition, exclude the checks for musl (incompatible sizes but compatible offsets)

Pass through LIBCXX_HAS_MUSL_LIBC to make check-msan/check-tsan able to build libc++ (https://bugs.llvm.org/show_bug.cgi?id=48618).

Many sanitizer features are available now.

```
% ninja check-asan
(known issues:
* ASAN_OPTIONS=fast_unwind_on_malloc=0 odr-violations hangs
)
...
Testing Time: 53.69s
  Unsupported      : 185
  Passed           : 512
  Expectedly Failed:   1
  Failed           :  12

% ninja check-ubsan check-ubsan-minimal check-memprof # all passed

% ninja check-cfi
( all cross-dso/)
...
Testing Time: 8.68s
  Unsupported      : 264
  Passed           :  80
  Expectedly Failed:   8
  Failed           :  32

% ninja check-msan
(Many are due to functions not marked unsupported.)
Testing Time: 23.09s
  Unsupported      :   6
  Passed           : 764
  Expectedly Failed:   2
  Failed           :  58

% ninja check-tsan
Testing Time: 23.21s
  Unsupported      :  86
  Passed           : 295
  Expectedly Failed:   1
  Failed           :  25
```

Used `ASAN_OPTIONS=verbosity=2` to verify no unneeded interceptors.

Partly based on Jari Ronkainen's https://reviews.llvm.org/D63785#1921014

Reviewed By: vitalybuka

Differential Revision: https://reviews.llvm.org/D93848
  • Loading branch information
MaskRay committed Dec 31, 2020
1 parent fd73980 commit a92d015
Show file tree
Hide file tree
Showing 13 changed files with 148 additions and 112 deletions.
1 change: 1 addition & 0 deletions compiler-rt/cmake/Modules/AddCompilerRT.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,7 @@ macro(add_custom_libcxx name prefix)
CMAKE_OBJDUMP
CMAKE_STRIP
CMAKE_SYSROOT
LIBCXX_HAS_MUSL_LIBC
PYTHON_EXECUTABLE
Python3_EXECUTABLE
Python2_EXECUTABLE
Expand Down
6 changes: 3 additions & 3 deletions compiler-rt/lib/asan/asan_interceptors.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ void InitializePlatformInterceptors();
# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0
#endif

#if (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_SOLARIS
#if SANITIZER_GLIBC || SANITIZER_SOLARIS
# define ASAN_INTERCEPT_SWAPCONTEXT 1
#else
# define ASAN_INTERCEPT_SWAPCONTEXT 0
Expand All @@ -72,7 +72,7 @@ void InitializePlatformInterceptors();
# define ASAN_INTERCEPT_SIGLONGJMP 0
#endif

#if SANITIZER_LINUX && !SANITIZER_ANDROID
#if SANITIZER_GLIBC
# define ASAN_INTERCEPT___LONGJMP_CHK 1
#else
# define ASAN_INTERCEPT___LONGJMP_CHK 0
Expand Down Expand Up @@ -106,7 +106,7 @@ void InitializePlatformInterceptors();
# define ASAN_INTERCEPT_ATEXIT 0
#endif

#if SANITIZER_LINUX && !SANITIZER_ANDROID
#if SANITIZER_GLIBC
# define ASAN_INTERCEPT___STRDUP 1
#else
# define ASAN_INTERCEPT___STRDUP 0
Expand Down
4 changes: 2 additions & 2 deletions compiler-rt/lib/asan/tests/asan_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -804,7 +804,7 @@ char* MallocAndMemsetString(size_t size) {
return MallocAndMemsetString(size, 'z');
}

#if defined(__linux__) && !defined(__ANDROID__)
#if SANITIZER_GLIBC
#define READ_TEST(READ_N_BYTES) \
char *x = new char[10]; \
int fd = open("/proc/self/stat", O_RDONLY); \
Expand All @@ -827,7 +827,7 @@ TEST(AddressSanitizer, pread64) {
TEST(AddressSanitizer, read) {
READ_TEST(read(fd, x, 15));
}
#endif // defined(__linux__) && !defined(__ANDROID__)
#endif // SANITIZER_GLIBC

// This test case fails
// Clang optimizes memcpy/memset calls which lead to unaligned access
Expand Down
6 changes: 3 additions & 3 deletions compiler-rt/lib/interception/interception_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ bool InterceptFunction(const char *name, uptr *ptr_to_real, uptr func,
return addr && (func == wrapper);
}

// Android and Solaris do not have dlvsym
#if !SANITIZER_ANDROID && !SANITIZER_SOLARIS
// dlvsym is a GNU extension supported by some other platforms.
#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
static void *GetFuncAddr(const char *name, const char *ver) {
return dlvsym(RTLD_NEXT, name, ver);
}
Expand All @@ -75,7 +75,7 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
*ptr_to_real = (uptr)addr;
return addr && (func == wrapper);
}
#endif // !SANITIZER_ANDROID
#endif // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD

} // namespace __interception

Expand Down
6 changes: 3 additions & 3 deletions compiler-rt/lib/interception/interception_linux.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
(::__interception::uptr) & (func), \
(::__interception::uptr) & WRAP(func))

// Android and Solaris do not have dlvsym
#if !SANITIZER_ANDROID && !SANITIZER_SOLARIS
// dlvsym is a GNU extension supported by some other platforms.
#if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD
#define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
::__interception::InterceptFunction( \
#func, symver, \
Expand All @@ -46,7 +46,7 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real,
#else
#define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)
#endif // !SANITIZER_ANDROID && !SANITIZER_SOLARIS
#endif // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD

#endif // INTERCEPTION_LINUX_H
#endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD ||
Expand Down
36 changes: 23 additions & 13 deletions compiler-rt/lib/msan/tests/msan_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ int shmdt(const void *);
}
#endif

#if defined(__linux__) && !defined(__GLIBC__) && !defined(__ANDROID__)
#define MUSL 1
#endif

#include <inttypes.h>
#include <stdlib.h>
#include <stdarg.h>
Expand Down Expand Up @@ -1162,7 +1166,7 @@ TEST(MemorySanitizer, gethostbyaddr) {
EXPECT_HOSTENT_NOT_POISONED(he);
}

#if !defined(__NetBSD__)
#if defined(__GLIBC__) || defined(__FreeBSD__)
TEST(MemorySanitizer, gethostent_r) {
sethostent(0);
char buf[2000];
Expand Down Expand Up @@ -1342,7 +1346,7 @@ TEST(MemorySanitizer, shmat) {
ASSERT_GT(res, -1);
}

#if !defined(__FreeBSD__) && !defined(__NetBSD__)
#ifdef __GLIBC__
TEST(MemorySanitizer, random_r) {
int32_t x;
char z[64];
Expand Down Expand Up @@ -1422,7 +1426,7 @@ TEST(MemorySanitizer, realpath_null) {
free(res);
}

#if !defined(__FreeBSD__) && !defined(__NetBSD__)
#ifdef __GLIBC__
TEST(MemorySanitizer, canonicalize_file_name) {
const char* relpath = ".";
char* res = canonicalize_file_name(relpath);
Expand Down Expand Up @@ -1798,12 +1802,15 @@ TEST_STRTO_INT(strtol, char, )
TEST_STRTO_INT(strtoll, char, )
TEST_STRTO_INT(strtoul, char, )
TEST_STRTO_INT(strtoull, char, )
#ifndef MUSL
TEST_STRTO_INT(strtouq, char, )
#endif

TEST_STRTO_FLOAT(strtof, char, )
TEST_STRTO_FLOAT(strtod, char, )
TEST_STRTO_FLOAT(strtold, char, )

#ifndef MUSL
TEST_STRTO_FLOAT_LOC(strtof_l, char, )
TEST_STRTO_FLOAT_LOC(strtod_l, char, )
TEST_STRTO_FLOAT_LOC(strtold_l, char, )
Expand All @@ -1812,6 +1819,7 @@ TEST_STRTO_INT_LOC(strtol_l, char, )
TEST_STRTO_INT_LOC(strtoll_l, char, )
TEST_STRTO_INT_LOC(strtoul_l, char, )
TEST_STRTO_INT_LOC(strtoull_l, char, )
#endif

TEST_STRTO_INT(wcstol, wchar_t, L)
TEST_STRTO_INT(wcstoll, wchar_t, L)
Expand All @@ -1822,6 +1830,7 @@ TEST_STRTO_FLOAT(wcstof, wchar_t, L)
TEST_STRTO_FLOAT(wcstod, wchar_t, L)
TEST_STRTO_FLOAT(wcstold, wchar_t, L)

#ifndef MUSL
TEST_STRTO_FLOAT_LOC(wcstof_l, wchar_t, L)
TEST_STRTO_FLOAT_LOC(wcstod_l, wchar_t, L)
TEST_STRTO_FLOAT_LOC(wcstold_l, wchar_t, L)
Expand All @@ -1830,6 +1839,7 @@ TEST_STRTO_INT_LOC(wcstol_l, wchar_t, L)
TEST_STRTO_INT_LOC(wcstoll_l, wchar_t, L)
TEST_STRTO_INT_LOC(wcstoul_l, wchar_t, L)
TEST_STRTO_INT_LOC(wcstoull_l, wchar_t, L)
#endif


TEST(MemorySanitizer, strtoimax) {
Expand Down Expand Up @@ -1973,17 +1983,15 @@ TEST(MemorySanitizer, lgammal_r) {
}
#endif

#if !defined(__FreeBSD__) && !defined(__NetBSD__)
#ifdef __GLIBC__
TEST(MemorySanitizer, drand48_r) {
struct drand48_data buf;
srand48_r(0, &buf);
double d;
drand48_r(&buf, &d);
EXPECT_NOT_POISONED(d);
}
#endif

#if !defined(__FreeBSD__) && !defined(__NetBSD__)
TEST(MemorySanitizer, lrand48_r) {
struct drand48_data buf;
srand48_r(0, &buf);
Expand Down Expand Up @@ -2334,7 +2342,7 @@ TEST(MemorySanitizer, getmntent) {
}
#endif

#if !defined(__FreeBSD__) && !defined(__NetBSD__)
#ifdef __GLIBC__
TEST(MemorySanitizer, getmntent_r) {
TempFstabFile fstabtmp;
ASSERT_TRUE(fstabtmp.Create());
Expand Down Expand Up @@ -3096,7 +3104,7 @@ static void GetProgramPath(char *buf, size_t sz) {
int res = sysctl(mib, 4, buf, &sz, NULL, 0);
ASSERT_EQ(0, res);
}
#elif defined(__GLIBC__)
#elif defined(__GLIBC__) || defined(MUSL)
static void GetProgramPath(char *buf, size_t sz) {
extern char *program_invocation_name;
int res = snprintf(buf, sz, "%s", program_invocation_name);
Expand Down Expand Up @@ -3370,7 +3378,7 @@ TEST(MemorySanitizer, pthread_attr_get) {
EXPECT_NOT_POISONED(v);
EXPECT_NOT_POISONED(w);
}
#if !defined(__NetBSD__)
#ifdef __GLIBC__
{
cpu_set_t v;
res = pthread_attr_getaffinity_np(&attr, sizeof(v), &v);
Expand Down Expand Up @@ -3484,7 +3492,7 @@ TEST(MemorySanitizer, valloc) {
free(a);
}

#if !defined(__FreeBSD__) && !defined(__NetBSD__)
#ifdef __GLIBC__
TEST(MemorySanitizer, pvalloc) {
uintptr_t PageSize = GetPageSize();
void *p = pvalloc(PageSize + 100);
Expand Down Expand Up @@ -3629,6 +3637,7 @@ TEST(MemorySanitizer, getpwent) {
EXPECT_NOT_POISONED(p->pw_uid);
}

#ifndef MUSL
TEST(MemorySanitizer, getpwent_r) {
struct passwd pwd;
struct passwd *pwdres;
Expand All @@ -3642,8 +3651,9 @@ TEST(MemorySanitizer, getpwent_r) {
EXPECT_NOT_POISONED(pwd.pw_uid);
EXPECT_NOT_POISONED(pwdres);
}
#endif

#if !defined(__FreeBSD__) && !defined(__NetBSD__)
#ifdef __GLIBC__
TEST(MemorySanitizer, fgetpwent) {
FILE *fp = fopen("/etc/passwd", "r");
struct passwd *p = fgetpwent(fp);
Expand All @@ -3666,7 +3676,7 @@ TEST(MemorySanitizer, getgrent) {
EXPECT_NOT_POISONED(p->gr_gid);
}

#if !defined(__FreeBSD__) && !defined(__NetBSD__)
#ifdef __GLIBC__
TEST(MemorySanitizer, fgetgrent) {
FILE *fp = fopen("/etc/group", "r");
struct group *grp = fgetgrent(fp);
Expand All @@ -3683,6 +3693,7 @@ TEST(MemorySanitizer, fgetgrent) {
}
#endif

#if defined(__GLIBC__) || defined(__FreeBSD__)
TEST(MemorySanitizer, getgrent_r) {
struct group grp;
struct group *grpres;
Expand All @@ -3697,7 +3708,6 @@ TEST(MemorySanitizer, getgrent_r) {
EXPECT_NOT_POISONED(grpres);
}

#if !defined(__FreeBSD__) && !defined(__NetBSD__)
TEST(MemorySanitizer, fgetgrent_r) {
FILE *fp = fopen("/etc/group", "r");
struct group grp;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -330,13 +330,17 @@ static void ioctl_table_fill() {
_(SOUND_PCM_WRITE_CHANNELS, WRITE, sizeof(int));
_(SOUND_PCM_WRITE_FILTER, WRITE, sizeof(int));
_(TCFLSH, NONE, 0);
#if SANITIZER_GLIBC
_(TCGETA, WRITE, struct_termio_sz);
#endif
_(TCGETS, WRITE, struct_termios_sz);
_(TCSBRK, NONE, 0);
_(TCSBRKP, NONE, 0);
#if SANITIZER_GLIBC
_(TCSETA, READ, struct_termio_sz);
_(TCSETAF, READ, struct_termio_sz);
_(TCSETAW, READ, struct_termio_sz);
#endif
_(TCSETS, READ, struct_termios_sz);
_(TCSETSF, READ, struct_termios_sz);
_(TCSETSW, READ, struct_termios_sz);
Expand Down Expand Up @@ -364,7 +368,7 @@ static void ioctl_table_fill() {
_(VT_WAITACTIVE, NONE, 0);
#endif

#if SANITIZER_LINUX && !SANITIZER_ANDROID
#if SANITIZER_GLIBC
// _(SIOCDEVPLIP, WRITE, struct_ifreq_sz); // the same as EQL_ENSLAVE
_(CYGETDEFTHRESH, WRITE, sizeof(int));
_(CYGETDEFTIMEOUT, WRITE, sizeof(int));
Expand Down
11 changes: 7 additions & 4 deletions compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,7 @@ __attribute__((unused)) static bool GetLibcVersion(int *major, int *minor,
#endif
}

#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO && \
!SANITIZER_NETBSD && !SANITIZER_SOLARIS
#if SANITIZER_GLIBC && !SANITIZER_GO
static uptr g_tls_size;

#ifdef __i386__
Expand Down Expand Up @@ -256,7 +255,7 @@ void InitTlsSize() {
}
#else
void InitTlsSize() { }
#endif
#endif // SANITIZER_GLIBC && !SANITIZER_GO

#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) || \
defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__) || \
Expand Down Expand Up @@ -523,11 +522,15 @@ uptr GetTlsSize() {
uptr addr, size;
GetTls(&addr, &size);
return size;
#elif defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
#elif SANITIZER_GLIBC
#if defined(__mips__) || defined(__powerpc64__) || SANITIZER_RISCV64
return RoundUpTo(g_tls_size + TlsPreTcbSize(), 16);
#else
return g_tls_size;
#endif
#else
return 0;
#endif
}
#endif

Expand Down
11 changes: 11 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,23 @@
# error "This operating system is not supported"
#endif

// Get __GLIBC__ on a glibc platform.
#if __has_include(<features.h>)
#include <features.h>
#endif

#if defined(__linux__)
# define SANITIZER_LINUX 1
#else
# define SANITIZER_LINUX 0
#endif

#if defined(__GLIBC__)
# define SANITIZER_GLIBC 1
#else
# define SANITIZER_GLIBC 0
#endif

#if defined(__FreeBSD__)
# define SANITIZER_FREEBSD 1
#else
Expand Down
Loading

0 comments on commit a92d015

Please sign in to comment.