Skip to content

Commit

Permalink
[Sanitizers] Basic sanitizer Solaris support (PR 33274)
Browse files Browse the repository at this point in the history
Summary:
This is the first mostly working version of the Sanitizer port to 32-bit Solaris/x86.
It is currently based on Solaris 11.4 Beta.

This part was initially developed inside libsanitizer in the GCC tree and should apply to
both.  Subsequent parts will address changes to clang, the compiler-rt build system
and testsuite.

I'm not yet sure what the right patch granularity is: if it's profitable to split the patch
up, I'd like to get guidance on how to do so.

Most of the changes are probably straightforward with a few exceptions:

* The Solaris syscall interface isn't stable, undocumented and can change within an
  OS release.  The stable interface is the libc interface, which I'm using here, if possible
  using the internal _-prefixed names.

* While the patch primarily target 32-bit x86, I've left a few sparc changes in.  They
  cannot currently be used with clang due to a backend limitation, but have worked
  fine inside the gcc tree.

* Some functions (e.g. largefile versions of functions like open64) only exist in 32-bit
  Solaris, so I've introduced a separate SANITIZER_SOLARIS32 to check for that.

The patch (with the subsequent ones to be submitted shortly) was tested
on i386-pc-solaris2.11.  Only a few failures remain, some of them analyzed, some
still TBD:

    AddressSanitizer-i386-sunos :: TestCases/Posix/concurrent_overflow.cc
    AddressSanitizer-i386-sunos :: TestCases/init-order-atexit.cc
    AddressSanitizer-i386-sunos :: TestCases/log-path_test.cc
    AddressSanitizer-i386-sunos :: TestCases/malloc-no-intercept.c
    AddressSanitizer-i386-sunos-dynamic :: TestCases/Posix/concurrent_overflow.cc
    AddressSanitizer-i386-sunos-dynamic :: TestCases/Posix/start-deactivated.cc
    AddressSanitizer-i386-sunos-dynamic :: TestCases/default_options.cc
    AddressSanitizer-i386-sunos-dynamic :: TestCases/init-order-atexit.cc
    AddressSanitizer-i386-sunos-dynamic :: TestCases/log-path_test.cc
    AddressSanitizer-i386-sunos-dynamic :: TestCases/malloc-no-intercept.c

   SanitizerCommon-Unit :: ./Sanitizer-i386-Test/MemoryMappingLayout.DumpListOfModules
    SanitizerCommon-Unit :: ./Sanitizer-i386-Test/SanitizerCommon.PthreadDestructorIterations

Maybe this is good enough the get the ball rolling.

Reviewers: kcc, alekseyshl

Reviewed By: alekseyshl

Subscribers: srhines, jyknight, kubamracek, krytarowski, fedor.sergeev, llvm-commits, #sanitizers

Tags: #sanitizers

Differential Revision: https://reviews.llvm.org/D40898

llvm-svn: 320740
  • Loading branch information
krytarowski committed Dec 14, 2017
1 parent 0f7b735 commit 271018d
Show file tree
Hide file tree
Showing 27 changed files with 1,450 additions and 120 deletions.
8 changes: 5 additions & 3 deletions compiler-rt/lib/asan/asan_interceptors.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,14 @@ void InitializePlatformInterceptors();
# define ASAN_INTERCEPT_FORK 0
#endif

#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
SANITIZER_SOLARIS
# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 1
#else
# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0
#endif

#if SANITIZER_LINUX && !SANITIZER_ANDROID
#if (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_SOLARIS
# define ASAN_INTERCEPT_SWAPCONTEXT 1
#else
# define ASAN_INTERCEPT_SWAPCONTEXT 0
Expand All @@ -81,7 +82,8 @@ void InitializePlatformInterceptors();

// Android bug: https://code.google.com/p/android/issues/detail?id=61799
#if ASAN_HAS_EXCEPTIONS && !SANITIZER_WINDOWS && \
!(SANITIZER_ANDROID && defined(__i386))
!(SANITIZER_ANDROID && defined(__i386)) && \
!SANITIZER_SOLARIS
# define ASAN_INTERCEPT___CXA_THROW 1
#else
# define ASAN_INTERCEPT___CXA_THROW 0
Expand Down
21 changes: 18 additions & 3 deletions compiler-rt/lib/asan/asan_linux.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
//===----------------------------------------------------------------------===//

#include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \
SANITIZER_SOLARIS

#include "asan_interceptors.h"
#include "asan_internal.h"
Expand All @@ -40,7 +41,11 @@
#include <sys/link_elf.h>
#endif

#if SANITIZER_ANDROID || SANITIZER_FREEBSD
#if SANITIZER_SOLARIS
#include <link.h>
#endif

#if SANITIZER_ANDROID || SANITIZER_FREEBSD || SANITIZER_SOLARIS
#include <ucontext.h>
extern "C" void* _DYNAMIC;
#elif SANITIZER_NETBSD
Expand Down Expand Up @@ -140,6 +145,9 @@ void AsanCheckIncompatibleRT() {}
#else
static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size,
void *data) {
VReport(2, "info->dlpi_name = %s\tinfo->dlpi_addr = %p\n",
info->dlpi_name, info->dlpi_addr);

// Continue until the first dynamic library is found
if (!info->dlpi_name || info->dlpi_name[0] == 0)
return 0;
Expand All @@ -157,6 +165,12 @@ static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size,
}
#endif

#if SANITIZER_SOLARIS
// Ignore executable on Solaris
if (info->dlpi_addr == 0)
return 0;
#endif

*(const char **)data = info->dlpi_name;
return 1;
}
Expand Down Expand Up @@ -235,4 +249,5 @@ void *AsanDlSymNext(const char *sym) {

} // namespace __asan

#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD ||
// SANITIZER_SOLARIS
4 changes: 2 additions & 2 deletions compiler-rt/lib/asan/asan_malloc_linux.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

#include "sanitizer_common/sanitizer_platform.h"
#if SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX || \
SANITIZER_NETBSD
SANITIZER_NETBSD || SANITIZER_SOLARIS

#include "sanitizer_common/sanitizer_tls_get_addr.h"
#include "asan_allocator.h"
Expand Down Expand Up @@ -236,4 +236,4 @@ void ReplaceSystemMalloc() {
#endif // SANITIZER_ANDROID

#endif // SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX ||
// SANITIZER_NETBSD
// SANITIZER_NETBSD || SANITIZER_SOLARIS
7 changes: 5 additions & 2 deletions compiler-rt/lib/interception/interception.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
#include "sanitizer_common/sanitizer_internal_defs.h"

#if !SANITIZER_LINUX && !SANITIZER_FREEBSD && !SANITIZER_MAC && \
!SANITIZER_NETBSD && !SANITIZER_WINDOWS && !SANITIZER_FUCHSIA
!SANITIZER_NETBSD && !SANITIZER_WINDOWS && !SANITIZER_FUCHSIA && \
!SANITIZER_SOLARIS
# error "Interception doesn't work on this operating system."
#endif

Expand Down Expand Up @@ -264,7 +265,9 @@ typedef unsigned long uptr; // NOLINT

#define INCLUDED_FROM_INTERCEPTION_LIB

#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD
#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
SANITIZER_SOLARIS

# include "interception_linux.h"
# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)
# define INTERCEPT_FUNCTION_VER(func, symver) \
Expand Down
9 changes: 6 additions & 3 deletions compiler-rt/lib/interception/interception_linux.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@

#include "interception.h"

#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD
#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
SANITIZER_SOLARIS

#include <dlfcn.h> // for dlsym() and dlvsym()

Expand All @@ -41,12 +42,14 @@ bool GetRealFunctionAddress(const char *func_name, uptr *func_addr,
return real == wrapper;
}

#if !SANITIZER_ANDROID // android does not have dlvsym
// Android and Solaris do not have dlvsym
#if !SANITIZER_ANDROID && !SANITIZER_SOLARIS
void *GetFuncAddrVer(const char *func_name, const char *ver) {
return dlvsym(RTLD_NEXT, func_name, ver);
}
#endif // !SANITIZER_ANDROID

} // namespace __interception

#endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD
#endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD ||
// SANITIZER_SOLARIS
11 changes: 7 additions & 4 deletions compiler-rt/lib/interception/interception_linux.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
// Linux-specific interception methods.
//===----------------------------------------------------------------------===//

#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD
#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \
SANITIZER_SOLARIS

#if !defined(INCLUDED_FROM_INTERCEPTION_LIB)
# error "interception_linux.h should be included from interception library only"
Expand All @@ -34,14 +35,16 @@ void *GetFuncAddrVer(const char *func_name, const char *ver);
(::__interception::uptr) & (func), \
(::__interception::uptr) & WRAP(func))

#if !SANITIZER_ANDROID // android does not have dlvsym
// Android and Solaris do not have dlvsym
#if !SANITIZER_ANDROID && !SANITIZER_SOLARIS
#define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
(::__interception::real_##func = (func##_f)( \
unsigned long)::__interception::GetFuncAddrVer(#func, symver))
#else
#define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \
INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)
#endif // !SANITIZER_ANDROID
#endif // !SANITIZER_ANDROID && !SANITIZER_SOLARIS

#endif // INTERCEPTION_LINUX_H
#endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD
#endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD ||
// SANITIZER_SOLARIS
50 changes: 38 additions & 12 deletions compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
Original file line number Diff line number Diff line change
Expand Up @@ -1217,12 +1217,14 @@ INTERCEPTOR(unsigned long, time, unsigned long *t) {
#if SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS
static void unpoison_tm(void *ctx, __sanitizer_tm *tm) {
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, tm, sizeof(*tm));
#if !SANITIZER_SOLARIS
if (tm->tm_zone) {
// Can not use COMMON_INTERCEPTOR_WRITE_RANGE here, because tm->tm_zone
// can point to shared memory and tsan would report a data race.
COMMON_INTERCEPTOR_INITIALIZE_RANGE(tm->tm_zone,
REAL(strlen(tm->tm_zone)) + 1);
}
#endif
}
INTERCEPTOR(__sanitizer_tm *, localtime, unsigned long *timep) {
void *ctx;
Expand Down Expand Up @@ -2113,6 +2115,18 @@ static void unpoison_glob_t(void *ctx, __sanitizer_glob_t *pglob) {
}
}

#if SANITIZER_SOLARIS
INTERCEPTOR(int, glob, const char *pattern, int flags,
int (*errfunc)(const char *epath, int eerrno),
__sanitizer_glob_t *pglob) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, glob, pattern, flags, errfunc, pglob);
COMMON_INTERCEPTOR_READ_STRING(ctx, pattern, 0);
int res = REAL(glob)(pattern, flags, errfunc, pglob);
if ((!res || res == glob_nomatch) && pglob) unpoison_glob_t(ctx, pglob);
return res;
}
#else
static THREADLOCAL __sanitizer_glob_t *pglob_copy;

static void wrapped_gl_closedir(void *dir) {
Expand Down Expand Up @@ -2176,7 +2190,14 @@ INTERCEPTOR(int, glob, const char *pattern, int flags,
if ((!res || res == glob_nomatch) && pglob) unpoison_glob_t(ctx, pglob);
return res;
}
#endif // SANITIZER_SOLARIS
#define INIT_GLOB \
COMMON_INTERCEPT_FUNCTION(glob);
#else // SANITIZER_INTERCEPT_GLOB
#define INIT_GLOB
#endif // SANITIZER_INTERCEPT_GLOB

#if SANITIZER_INTERCEPT_GLOB64
INTERCEPTOR(int, glob64, const char *pattern, int flags,
int (*errfunc)(const char *epath, int eerrno),
__sanitizer_glob_t *pglob) {
Expand Down Expand Up @@ -2205,12 +2226,11 @@ INTERCEPTOR(int, glob64, const char *pattern, int flags,
if ((!res || res == glob_nomatch) && pglob) unpoison_glob_t(ctx, pglob);
return res;
}
#define INIT_GLOB \
COMMON_INTERCEPT_FUNCTION(glob); \
#define INIT_GLOB64 \
COMMON_INTERCEPT_FUNCTION(glob64);
#else // SANITIZER_INTERCEPT_GLOB
#define INIT_GLOB
#endif // SANITIZER_INTERCEPT_GLOB
#else // SANITIZER_INTERCEPT_GLOB64
#define INIT_GLOB64
#endif // SANITIZER_INTERCEPT_GLOB64

#if SANITIZER_INTERCEPT_WAIT
// According to sys/wait.h, wait(), waitid(), waitpid() may have symbol version
Expand Down Expand Up @@ -2515,22 +2535,26 @@ INTERCEPTOR(struct __sanitizer_hostent *, gethostent, int fake) {
if (res) write_hostent(ctx, res);
return res;
}
#define INIT_GETHOSTBYNAME \
COMMON_INTERCEPT_FUNCTION(gethostent); \
COMMON_INTERCEPT_FUNCTION(gethostbyaddr); \
COMMON_INTERCEPT_FUNCTION(gethostbyname);
#else
#define INIT_GETHOSTBYNAME
#endif // SANITIZER_INTERCEPT_GETHOSTBYNAME

#if SANITIZER_INTERCEPT_GETHOSTBYNAME2
INTERCEPTOR(struct __sanitizer_hostent *, gethostbyname2, char *name, int af) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, gethostbyname2, name, af);
struct __sanitizer_hostent *res = REAL(gethostbyname2)(name, af);
if (res) write_hostent(ctx, res);
return res;
}
#define INIT_GETHOSTBYNAME \
COMMON_INTERCEPT_FUNCTION(gethostent); \
COMMON_INTERCEPT_FUNCTION(gethostbyaddr); \
COMMON_INTERCEPT_FUNCTION(gethostbyname); \
COMMON_INTERCEPT_FUNCTION(gethostbyname2);
#define INIT_GETHOSTBYNAME2 COMMON_INTERCEPT_FUNCTION(gethostbyname2);
#else
#define INIT_GETHOSTBYNAME
#endif
#define INIT_GETHOSTBYNAME2
#endif // SANITIZER_INTERCEPT_GETHOSTBYNAME2

#if SANITIZER_INTERCEPT_GETHOSTBYNAME_R
INTERCEPTOR(int, gethostbyname_r, char *name, struct __sanitizer_hostent *ret,
Expand Down Expand Up @@ -6384,6 +6408,7 @@ static void InitializeCommonInterceptors() {
INIT_GETITIMER;
INIT_TIME;
INIT_GLOB;
INIT_GLOB64;
INIT_WAIT;
INIT_WAIT4;
INIT_INET;
Expand All @@ -6392,6 +6417,7 @@ static void InitializeCommonInterceptors() {
INIT_GETNAMEINFO;
INIT_GETSOCKNAME;
INIT_GETHOSTBYNAME;
INIT_GETHOSTBYNAME2;
INIT_GETHOSTBYNAME_R;
INIT_GETHOSTBYNAME2_R;
INIT_GETHOSTBYADDR_R;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ static void ioctl_table_fill() {
_(SIOCGIFCONF, CUSTOM, 0);
_(SIOCGPGRP, WRITE, sizeof(int));
_(SIOCSPGRP, READ, sizeof(int));
#if !SANITIZER_SOLARIS
_(TIOCCONS, NONE, 0);
#endif
_(TIOCEXCL, NONE, 0);
_(TIOCGETD, WRITE, sizeof(int));
_(TIOCGPGRP, WRITE, pid_t_sz);
Expand Down
2 changes: 2 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_errno.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
# define __errno_location __error
#elif SANITIZER_ANDROID || SANITIZER_NETBSD
# define __errno_location __errno
#elif SANITIZER_SOLARIS
# define __errno_location ___errno
#elif SANITIZER_WINDOWS
# define __errno_location _errno
#endif
Expand Down
10 changes: 9 additions & 1 deletion compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
// SANITIZER_SUPPORTS_WEAK_HOOKS means that we support real weak functions that
// will evaluate to a null pointer when not defined.
#ifndef SANITIZER_SUPPORTS_WEAK_HOOKS
#if (SANITIZER_LINUX || SANITIZER_MAC) && !SANITIZER_GO
#if (SANITIZER_LINUX || SANITIZER_MAC || SANITIZER_SOLARIS) && !SANITIZER_GO
# define SANITIZER_SUPPORTS_WEAK_HOOKS 1
#else
# define SANITIZER_SUPPORTS_WEAK_HOOKS 0
Expand All @@ -91,6 +91,10 @@
// FIXME: do we have anything like this on Mac?
#if SANITIZER_LINUX && !SANITIZER_ANDROID && !defined(PIC)
# define SANITIZER_CAN_USE_PREINIT_ARRAY 1
// Before Solaris 11.4, .preinit_array is fully supported only with GNU ld.
// FIXME: Check for those conditions.
#elif SANITIZER_SOLARIS && !defined(PIC)
# define SANITIZER_CAN_USE_PREINIT_ARRAY 1
#else
# define SANITIZER_CAN_USE_PREINIT_ARRAY 0
#endif
Expand Down Expand Up @@ -137,7 +141,11 @@ typedef unsigned error_t;
typedef int fd_t;
typedef int error_t;
#endif
#if SANITIZER_SOLARIS && !defined(_LP64)
typedef long pid_t;
#else
typedef int pid_t;
#endif

#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_MAC || \
(SANITIZER_LINUX && defined(__x86_64__))
Expand Down
Loading

0 comments on commit 271018d

Please sign in to comment.