aboutsummaryrefslogtreecommitdiff
path: root/lib/sanitizer_common
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sanitizer_common')
-rw-r--r--lib/sanitizer_common/CMakeLists.txt1
-rw-r--r--lib/sanitizer_common/sanitizer_common.cc42
-rw-r--r--lib/sanitizer_common/sanitizer_common.h6
-rw-r--r--lib/sanitizer_common/sanitizer_common_libcdep.cc2
-rw-r--r--lib/sanitizer_common/sanitizer_common_syscalls.inc6
-rw-r--r--lib/sanitizer_common/sanitizer_coverage_libcdep.cc23
-rw-r--r--lib/sanitizer_common/sanitizer_flag_parser.h2
-rw-r--r--lib/sanitizer_common/sanitizer_flags.cc2
-rw-r--r--lib/sanitizer_common/sanitizer_flags.inc1
-rw-r--r--lib/sanitizer_common/sanitizer_interface_internal.h58
-rw-r--r--lib/sanitizer_common/sanitizer_internal_defs.h35
-rw-r--r--lib/sanitizer_common/sanitizer_libignore.cc26
-rw-r--r--lib/sanitizer_common/sanitizer_libignore.h9
-rw-r--r--lib/sanitizer_common/sanitizer_linux.cc7
-rw-r--r--lib/sanitizer_common/sanitizer_linux.h2
-rw-r--r--lib/sanitizer_common/sanitizer_linux_libcdep.cc44
-rw-r--r--lib/sanitizer_common/sanitizer_platform_interceptors.h2
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_posix.cc18
-rw-r--r--lib/sanitizer_common/sanitizer_platform_limits_posix.h6
-rw-r--r--lib/sanitizer_common/sanitizer_posix.cc7
-rw-r--r--lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc146
-rw-r--r--lib/sanitizer_common/sanitizer_suppressions.cc129
-rw-r--r--lib/sanitizer_common/sanitizer_suppressions.h50
-rw-r--r--lib/sanitizer_common/sanitizer_symbolizer_win.cc72
-rw-r--r--lib/sanitizer_common/sanitizer_syscall_generic.inc4
-rw-r--r--lib/sanitizer_common/sanitizer_win.cc6
-rw-r--r--lib/sanitizer_common/tests/sanitizer_linux_test.cc8
-rw-r--r--lib/sanitizer_common/tests/sanitizer_suppressions_test.cc106
28 files changed, 449 insertions, 371 deletions
diff --git a/lib/sanitizer_common/CMakeLists.txt b/lib/sanitizer_common/CMakeLists.txt
index 86697e7f7c40..6eb6ca8fc900 100644
--- a/lib/sanitizer_common/CMakeLists.txt
+++ b/lib/sanitizer_common/CMakeLists.txt
@@ -67,6 +67,7 @@ set(SANITIZER_HEADERS
sanitizer_flag_parser.h
sanitizer_flags.h
sanitizer_flags.inc
+ sanitizer_interface_internal.h
sanitizer_internal_defs.h
sanitizer_lfstack.h
sanitizer_libc.h
diff --git a/lib/sanitizer_common/sanitizer_common.cc b/lib/sanitizer_common/sanitizer_common.cc
index 489081e0760b..4be3c7abf756 100644
--- a/lib/sanitizer_common/sanitizer_common.cc
+++ b/lib/sanitizer_common/sanitizer_common.cc
@@ -288,6 +288,48 @@ void DecreaseTotalMmap(uptr size) {
atomic_fetch_sub(&g_total_mmaped, size, memory_order_relaxed);
}
+bool TemplateMatch(const char *templ, const char *str) {
+ if (str == 0 || str[0] == 0)
+ return false;
+ bool start = false;
+ if (templ && templ[0] == '^') {
+ start = true;
+ templ++;
+ }
+ bool asterisk = false;
+ while (templ && templ[0]) {
+ if (templ[0] == '*') {
+ templ++;
+ start = false;
+ asterisk = true;
+ continue;
+ }
+ if (templ[0] == '$')
+ return str[0] == 0 || asterisk;
+ if (str[0] == 0)
+ return false;
+ char *tpos = (char*)internal_strchr(templ, '*');
+ char *tpos1 = (char*)internal_strchr(templ, '$');
+ if (tpos == 0 || (tpos1 && tpos1 < tpos))
+ tpos = tpos1;
+ if (tpos != 0)
+ tpos[0] = 0;
+ const char *str0 = str;
+ const char *spos = internal_strstr(str, templ);
+ str = spos + internal_strlen(templ);
+ templ = tpos;
+ if (tpos)
+ tpos[0] = tpos == tpos1 ? '$' : '*';
+ if (spos == 0)
+ return false;
+ if (start && spos != str0)
+ return false;
+ start = false;
+ asterisk = false;
+ }
+ return true;
+}
+
} // namespace __sanitizer
using namespace __sanitizer; // NOLINT
diff --git a/lib/sanitizer_common/sanitizer_common.h b/lib/sanitizer_common/sanitizer_common.h
index 720cd73a43c5..ff13ef164045 100644
--- a/lib/sanitizer_common/sanitizer_common.h
+++ b/lib/sanitizer_common/sanitizer_common.h
@@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//
//
-// This file is shared between AddressSanitizer and ThreadSanitizer
-// run-time libraries.
+// This file is shared between run-time libraries of sanitizers.
+//
// It declares common functions and classes that are used in both runtimes.
// Implementation of some functions are provided in sanitizer_common, while
// others must be defined by run-time library itself.
@@ -17,6 +17,7 @@
#define SANITIZER_COMMON_H
#include "sanitizer_flags.h"
+#include "sanitizer_interface_internal.h"
#include "sanitizer_internal_defs.h"
#include "sanitizer_libc.h"
#include "sanitizer_list.h"
@@ -241,6 +242,7 @@ void SleepForMillis(int millis);
u64 NanoTime();
int Atexit(void (*function)(void));
void SortArray(uptr *array, uptr size);
+bool TemplateMatch(const char *templ, const char *str);
// Exit
void NORETURN Abort();
diff --git a/lib/sanitizer_common/sanitizer_common_libcdep.cc b/lib/sanitizer_common/sanitizer_common_libcdep.cc
index e357e1cbbfc9..17ef6897ba26 100644
--- a/lib/sanitizer_common/sanitizer_common_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_common_libcdep.cc
@@ -121,7 +121,7 @@ void MaybeStartBackgroudThread() {
// Start the background thread if one of the rss limits is given.
if (!common_flags()->hard_rss_limit_mb &&
!common_flags()->soft_rss_limit_mb) return;
- if (!real_pthread_create) return; // Can't spawn the thread anyway.
+ if (!&real_pthread_create) return; // Can't spawn the thread anyway.
internal_start_thread(BackgroundThread, nullptr);
}
diff --git a/lib/sanitizer_common/sanitizer_common_syscalls.inc b/lib/sanitizer_common/sanitizer_common_syscalls.inc
index a52338b62f5e..7e15d51ff35b 100644
--- a/lib/sanitizer_common/sanitizer_common_syscalls.inc
+++ b/lib/sanitizer_common/sanitizer_common_syscalls.inc
@@ -2297,7 +2297,8 @@ PRE_SYSCALL(ni_syscall)() {}
POST_SYSCALL(ni_syscall)(long res) {}
PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) {
-#if !SANITIZER_ANDROID && (defined(__i386) || defined (__x86_64))
+#if !SANITIZER_ANDROID && \
+ (defined(__i386) || defined(__x86_64) || defined(__mips64))
if (data) {
if (request == ptrace_setregs) {
PRE_READ((void *)data, struct_user_regs_struct_sz);
@@ -2316,7 +2317,8 @@ PRE_SYSCALL(ptrace)(long request, long pid, long addr, long data) {
}
POST_SYSCALL(ptrace)(long res, long request, long pid, long addr, long data) {
-#if !SANITIZER_ANDROID && (defined(__i386) || defined (__x86_64))
+#if !SANITIZER_ANDROID && \
+ (defined(__i386) || defined(__x86_64) || defined(__mips64))
if (res >= 0 && data) {
// Note that this is different from the interceptor in
// sanitizer_common_interceptors.inc.
diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
index e8f42f68a42f..49887b1e91a9 100644
--- a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
@@ -82,7 +82,7 @@ class CoverageData {
void TraceBasicBlock(s32 *id);
void InitializeGuardArray(s32 *guards);
- void InitializeGuards(s32 *guards, uptr n);
+ void InitializeGuards(s32 *guards, uptr n, const char *module_name);
void ReinitializeGuards();
uptr *data();
@@ -110,6 +110,9 @@ class CoverageData {
// Vector of coverage guard arrays, protected by mu.
InternalMmapVectorNoCtor<s32*> guard_array_vec;
+ // Vector of module (compilation unit) names.
+ InternalMmapVectorNoCtor<const char*> comp_unit_name_vec;
+
// Caller-Callee (cc) array, size and current index.
static const uptr kCcArrayMaxSize = FIRST_32_SECOND_64(1 << 18, 1 << 24);
uptr **cc_array;
@@ -286,13 +289,15 @@ void CoverageData::Extend(uptr npcs) {
atomic_store(&pc_array_size, size, memory_order_release);
}
-void CoverageData::InitializeGuards(s32 *guards, uptr n) {
+void CoverageData::InitializeGuards(s32 *guards, uptr n,
+ const char *module_name) {
// The array 'guards' has n+1 elements, we use the element zero
// to store 'n'.
CHECK_LT(n, 1 << 30);
guards[0] = static_cast<s32>(n);
InitializeGuardArray(guards);
SpinMutexLock l(&mu);
+ comp_unit_name_vec.push_back(module_name);
guard_array_vec.push_back(guards);
}
@@ -450,6 +455,14 @@ void CoverageData::DumpTrace() {
internal_write(fd, out.data(), out.length());
internal_close(fd);
+ fd = CovOpenFile(false, "trace-compunits");
+ if (fd < 0) return;
+ out.clear();
+ for (uptr i = 0; i < comp_unit_name_vec.size(); i++)
+ out.append("%s\n", comp_unit_name_vec[i]);
+ internal_write(fd, out.data(), out.length());
+ internal_close(fd);
+
fd = CovOpenFile(false, "trace-events");
if (fd < 0) return;
uptr bytes_to_write = max_idx * sizeof(tr_event_array[0]);
@@ -675,9 +688,9 @@ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init() {
coverage_data.Init();
}
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { CovDump(); }
-SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_module_init(s32 *guards,
- uptr npcs) {
- coverage_data.InitializeGuards(guards, npcs);
+SANITIZER_INTERFACE_ATTRIBUTE void
+__sanitizer_cov_module_init(s32 *guards, uptr npcs, const char *module_name) {
+ coverage_data.InitializeGuards(guards, npcs, module_name);
if (!common_flags()->coverage_direct) return;
if (SANITIZER_ANDROID && coverage_enabled) {
// dlopen/dlclose interceptors do not work on Android, so we rely on
diff --git a/lib/sanitizer_common/sanitizer_flag_parser.h b/lib/sanitizer_common/sanitizer_flag_parser.h
index 87afb8238c01..0ac7634cb876 100644
--- a/lib/sanitizer_common/sanitizer_flag_parser.h
+++ b/lib/sanitizer_common/sanitizer_flag_parser.h
@@ -31,7 +31,7 @@ class FlagHandler : public FlagHandlerBase {
public:
explicit FlagHandler(T *t) : t_(t) {}
- bool Parse(const char *value);
+ bool Parse(const char *value) final;
};
template <>
diff --git a/lib/sanitizer_common/sanitizer_flags.cc b/lib/sanitizer_common/sanitizer_flags.cc
index a2965351cf2a..e835b46a24fc 100644
--- a/lib/sanitizer_common/sanitizer_flags.cc
+++ b/lib/sanitizer_common/sanitizer_flags.cc
@@ -51,7 +51,7 @@ class FlagHandlerInclude : public FlagHandlerBase {
public:
explicit FlagHandlerInclude(FlagParser *parser) : parser_(parser) {}
- bool Parse(const char *value) {
+ bool Parse(const char *value) final {
char *data;
uptr data_mapped_size;
int err;
diff --git a/lib/sanitizer_common/sanitizer_flags.inc b/lib/sanitizer_common/sanitizer_flags.inc
index e8c8a87537d7..58f7f372228f 100644
--- a/lib/sanitizer_common/sanitizer_flags.inc
+++ b/lib/sanitizer_common/sanitizer_flags.inc
@@ -128,7 +128,6 @@ COMMON_FLAG(const char *, coverage_dir, ".",
COMMON_FLAG(bool, full_address_space, false,
"Sanitize complete address space; "
"by default kernel area on 32-bit platforms will not be sanitized")
-COMMON_FLAG(const char *, suppressions, "", "Suppressions file name.")
COMMON_FLAG(bool, print_suppressions, true,
"Print matched suppressions at exit.")
COMMON_FLAG(
diff --git a/lib/sanitizer_common/sanitizer_interface_internal.h b/lib/sanitizer_common/sanitizer_interface_internal.h
new file mode 100644
index 000000000000..94d9f4e9524a
--- /dev/null
+++ b/lib/sanitizer_common/sanitizer_interface_internal.h
@@ -0,0 +1,58 @@
+//===-- sanitizer_interface_internal.h --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between run-time libraries of sanitizers.
+//
+// This header declares the sanitizer runtime interface functions.
+// The runtime library has to define these functions so the instrumented program
+// could call them.
+//
+// See also include/sanitizer/common_interface_defs.h
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_INTERFACE_INTERNAL_H
+#define SANITIZER_INTERFACE_INTERNAL_H
+
+#include "sanitizer_internal_defs.h"
+
+extern "C" {
+ // Tell the tools to write their reports to "path.<pid>" instead of stderr.
+ // The special values are "stdout" and "stderr".
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __sanitizer_set_report_path(const char *path);
+
+ typedef struct {
+ int coverage_sandboxed;
+ __sanitizer::sptr coverage_fd;
+ unsigned int coverage_max_block_size;
+ } __sanitizer_sandbox_arguments;
+
+ // Notify the tools that the sandbox is going to be turned on.
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void
+ __sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args);
+
+ // This function is called by the tool when it has just finished reporting
+ // an error. 'error_summary' is a one-line string that summarizes
+ // the error message. This function can be overridden by the client.
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ void __sanitizer_report_error_summary(const char *error_summary);
+
+ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump();
+ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init();
+ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(__sanitizer::u32 *guard);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __sanitizer_annotate_contiguous_container(const void *beg,
+ const void *end,
+ const void *old_mid,
+ const void *new_mid);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ int __sanitizer_verify_contiguous_container(const void *beg, const void *mid,
+ const void *end);
+} // extern "C"
+
+#endif // SANITIZER_INTERFACE_INTERNAL_H
diff --git a/lib/sanitizer_common/sanitizer_internal_defs.h b/lib/sanitizer_common/sanitizer_internal_defs.h
index 2a0b41f0bb99..a969f305cd1a 100644
--- a/lib/sanitizer_common/sanitizer_internal_defs.h
+++ b/lib/sanitizer_common/sanitizer_internal_defs.h
@@ -101,41 +101,6 @@ typedef u32 operator_new_size_type;
#endif
} // namespace __sanitizer
-extern "C" {
- // Tell the tools to write their reports to "path.<pid>" instead of stderr.
- // The special values are "stdout" and "stderr".
- SANITIZER_INTERFACE_ATTRIBUTE
- void __sanitizer_set_report_path(const char *path);
-
- typedef struct {
- int coverage_sandboxed;
- __sanitizer::sptr coverage_fd;
- unsigned int coverage_max_block_size;
- } __sanitizer_sandbox_arguments;
-
- // Notify the tools that the sandbox is going to be turned on.
- SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void
- __sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args);
-
- // This function is called by the tool when it has just finished reporting
- // an error. 'error_summary' is a one-line string that summarizes
- // the error message. This function can be overridden by the client.
- SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
- void __sanitizer_report_error_summary(const char *error_summary);
-
- SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump();
- SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init();
- SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(__sanitizer::u32 *guard);
- SANITIZER_INTERFACE_ATTRIBUTE
- void __sanitizer_annotate_contiguous_container(const void *beg,
- const void *end,
- const void *old_mid,
- const void *new_mid);
- SANITIZER_INTERFACE_ATTRIBUTE
- int __sanitizer_verify_contiguous_container(const void *beg, const void *mid,
- const void *end);
-} // extern "C"
-
using namespace __sanitizer; // NOLINT
// ----------- ATTENTION -------------
diff --git a/lib/sanitizer_common/sanitizer_libignore.cc b/lib/sanitizer_common/sanitizer_libignore.cc
index 8df0467b1e9b..cefb1dc97a17 100644
--- a/lib/sanitizer_common/sanitizer_libignore.cc
+++ b/lib/sanitizer_common/sanitizer_libignore.cc
@@ -19,24 +19,18 @@ namespace __sanitizer {
LibIgnore::LibIgnore(LinkerInitialized) {
}
-void LibIgnore::Init(const SuppressionContext &supp) {
+void LibIgnore::AddIgnoredLibrary(const char *name_templ) {
BlockingMutexLock lock(&mutex_);
- CHECK_EQ(count_, 0);
- const uptr n = supp.SuppressionCount();
- for (uptr i = 0; i < n; i++) {
- const Suppression *s = supp.SuppressionAt(i);
- if (s->type != SuppressionLib)
- continue;
- if (count_ >= kMaxLibs) {
- Report("%s: too many called_from_lib suppressions (max: %d)\n",
- SanitizerToolName, kMaxLibs);
- Die();
- }
- Lib *lib = &libs_[count_++];
- lib->templ = internal_strdup(s->templ);
- lib->name = 0;
- lib->loaded = false;
+ if (count_ >= kMaxLibs) {
+ Report("%s: too many ignored libraries (max: %d)\n", SanitizerToolName,
+ kMaxLibs);
+ Die();
}
+ Lib *lib = &libs_[count_++];
+ lib->templ = internal_strdup(name_templ);
+ lib->name = nullptr;
+ lib->real_name = nullptr;
+ lib->loaded = false;
}
void LibIgnore::OnLibraryLoaded(const char *name) {
diff --git a/lib/sanitizer_common/sanitizer_libignore.h b/lib/sanitizer_common/sanitizer_libignore.h
index 8e1d584d8e3c..cd56c36c1c0e 100644
--- a/lib/sanitizer_common/sanitizer_libignore.h
+++ b/lib/sanitizer_common/sanitizer_libignore.h
@@ -8,8 +8,8 @@
//===----------------------------------------------------------------------===//
//
// LibIgnore allows to ignore all interceptors called from a particular set
-// of dynamic libraries. LibIgnore remembers all "called_from_lib" suppressions
-// from the provided SuppressionContext; finds code ranges for the libraries;
+// of dynamic libraries. LibIgnore can be initialized with several templates
+// of names of libraries to be ignored. It finds code ranges for the libraries;
// and checks whether the provided PC value belongs to the code ranges.
//
//===----------------------------------------------------------------------===//
@@ -19,7 +19,6 @@
#include "sanitizer_internal_defs.h"
#include "sanitizer_common.h"
-#include "sanitizer_suppressions.h"
#include "sanitizer_atomic.h"
#include "sanitizer_mutex.h"
@@ -29,8 +28,8 @@ class LibIgnore {
public:
explicit LibIgnore(LinkerInitialized);
- // Fetches all "called_from_lib" suppressions from the SuppressionContext.
- void Init(const SuppressionContext &supp);
+ // Must be called during initialization.
+ void AddIgnoredLibrary(const char *name_templ);
// Must be called after a new dynamic library is loaded.
void OnLibraryLoaded(const char *name);
diff --git a/lib/sanitizer_common/sanitizer_linux.cc b/lib/sanitizer_common/sanitizer_linux.cc
index 26138ba29d35..8029181a5173 100644
--- a/lib/sanitizer_common/sanitizer_linux.cc
+++ b/lib/sanitizer_common/sanitizer_linux.cc
@@ -860,6 +860,13 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
: "rsp", "memory", "r11", "rcx");
return res;
}
+#elif defined(__mips__)
+// TODO(sagarthakur): clone function is to be rewritten in assembly.
+uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
+ int *parent_tidptr, void *newtls, int *child_tidptr) {
+ return clone(fn, child_stack, flags, arg, parent_tidptr,
+ newtls, child_tidptr);
+}
#endif // defined(__x86_64__) && SANITIZER_LINUX
#if SANITIZER_ANDROID
diff --git a/lib/sanitizer_common/sanitizer_linux.h b/lib/sanitizer_common/sanitizer_linux.h
index 3013c25f7c38..b2e603d3a23e 100644
--- a/lib/sanitizer_common/sanitizer_linux.h
+++ b/lib/sanitizer_common/sanitizer_linux.h
@@ -43,7 +43,7 @@ uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5);
// internal_sigaction instead.
int internal_sigaction_norestorer(int signum, const void *act, void *oldact);
void internal_sigdelset(__sanitizer_sigset_t *set, int signum);
-#if defined(__x86_64__)
+#if defined(__x86_64__) || defined(__mips__)
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
int *parent_tidptr, void *newtls, int *child_tidptr);
#endif
diff --git a/lib/sanitizer_common/sanitizer_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_linux_libcdep.cc
index df42c3604ae9..c71b6257ebc3 100644
--- a/lib/sanitizer_common/sanitizer_linux_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_linux_libcdep.cc
@@ -168,6 +168,20 @@ static uptr g_tls_size;
# define DL_INTERNAL_FUNCTION
#endif
+#if defined(__mips__)
+// TlsPreTcbSize includes size of struct pthread_descr and size of tcb
+// head structure. It lies before the static tls blocks.
+static uptr TlsPreTcbSize() {
+ const uptr kTcbHead = 16;
+ const uptr kTlsAlign = 16;
+ const uptr kTlsPreTcbSize =
+ (ThreadDescriptorSize() + kTcbHead + kTlsAlign - 1) & ~(kTlsAlign - 1);
+ InitTlsSize();
+ g_tls_size = (g_tls_size + kTlsPreTcbSize + kTlsAlign -1) & ~(kTlsAlign - 1);
+ return kTlsPreTcbSize;
+}
+#endif
+
void InitTlsSize() {
#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO
typedef void (*get_tls_func)(size_t*, size_t*) DL_INTERNAL_FUNCTION;
@@ -184,7 +198,8 @@ void InitTlsSize() {
#endif // !SANITIZER_FREEBSD && !SANITIZER_ANDROID
}
-#if (defined(__x86_64__) || defined(__i386__)) && SANITIZER_LINUX
+#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__)) \
+ && SANITIZER_LINUX
// sizeof(struct thread) from glibc.
static atomic_uintptr_t kThreadDescriptorSize;
@@ -192,6 +207,7 @@ uptr ThreadDescriptorSize() {
uptr val = atomic_load(&kThreadDescriptorSize, memory_order_relaxed);
if (val)
return val;
+#if defined(__x86_64__) || defined(__i386__)
#ifdef _CS_GNU_LIBC_VERSION
char buf[64];
uptr len = confstr(_CS_GNU_LIBC_VERSION, buf, sizeof(buf));
@@ -224,6 +240,13 @@ uptr ThreadDescriptorSize() {
return val;
}
#endif
+#elif defined(__mips__)
+ // TODO(sagarthakur): add more values as per different glibc versions.
+ val = FIRST_32_SECOND_64(1152, 1776);
+ if (val)
+ atomic_store(&kThreadDescriptorSize, val, memory_order_relaxed);
+ return val;
+#endif
return 0;
}
@@ -240,12 +263,24 @@ uptr ThreadSelf() {
asm("mov %%gs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
# elif defined(__x86_64__)
asm("mov %%fs:%c1,%0" : "=r"(descr_addr) : "i"(kThreadSelfOffset));
+# elif defined(__mips__)
+ // MIPS uses TLS variant I. The thread pointer (in hardware register $29)
+ // points to the end of the TCB + 0x7000. The pthread_descr structure is
+ // immediately in front of the TCB. TlsPreTcbSize() includes the size of the
+ // TCB and the size of pthread_descr.
+ const uptr kTlsTcbOffset = 0x7000;
+ uptr thread_pointer;
+ asm volatile(".set push;\
+ .set mips64r2;\
+ rdhwr %0,$29;\
+ .set pop" : "=r" (thread_pointer));
+ descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize();
# else
# error "unsupported CPU arch"
# endif
return descr_addr;
}
-#endif // (defined(__x86_64__) || defined(__i386__)) && SANITIZER_LINUX
+#endif // (x86_64 || i386 || MIPS) && SANITIZER_LINUX
#if SANITIZER_FREEBSD
static void **ThreadSelfSegbase() {
@@ -275,6 +310,9 @@ static void GetTls(uptr *addr, uptr *size) {
*size = GetTlsSize();
*addr -= *size;
*addr += ThreadDescriptorSize();
+# elif defined(__mips__)
+ *addr = ThreadSelf();
+ *size = GetTlsSize();
# else
*addr = 0;
*size = 0;
@@ -298,6 +336,7 @@ static void GetTls(uptr *addr, uptr *size) {
}
#endif
+#if !SANITIZER_GO
uptr GetTlsSize() {
#if SANITIZER_FREEBSD
uptr addr, size;
@@ -307,6 +346,7 @@ uptr GetTlsSize() {
return g_tls_size;
#endif
}
+#endif
void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
uptr *tls_addr, uptr *tls_size) {
diff --git a/lib/sanitizer_common/sanitizer_platform_interceptors.h b/lib/sanitizer_common/sanitizer_platform_interceptors.h
index 54a1cfd8582b..438ecbaa2ec8 100644
--- a/lib/sanitizer_common/sanitizer_platform_interceptors.h
+++ b/lib/sanitizer_common/sanitizer_platform_interceptors.h
@@ -127,7 +127,7 @@
#define SANITIZER_INTERCEPT_READDIR SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_READDIR64 SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_PTRACE SI_LINUX_NOT_ANDROID && \
- (defined(__i386) || defined (__x86_64)) // NOLINT
+ (defined(__i386) || defined (__x86_64) || defined (__mips64)) // NOLINT
#define SANITIZER_INTERCEPT_SETLOCALE SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_GETCWD SI_NOT_WINDOWS
#define SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME SI_LINUX_NOT_ANDROID
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
index 4eabcd7a3d22..8824c8088f2d 100644
--- a/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
+++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.cc
@@ -97,7 +97,6 @@
# include <sys/link_elf.h>
# include <netinet/ip_mroute.h>
# include <netinet/in.h>
-# include <netinet/ip_compat.h>
# include <net/ethernet.h>
# include <net/ppp_defs.h>
# include <glob.h>
@@ -117,6 +116,9 @@
#if SANITIZER_LINUX || SANITIZER_FREEBSD
# include <utime.h>
# include <sys/ptrace.h>
+# if defined(__mips64)
+# include <asm/ptrace.h>
+# endif
#endif
#if !SANITIZER_ANDROID
@@ -140,6 +142,9 @@
#include <sys/shm.h>
#include <sys/statvfs.h>
#include <sys/timex.h>
+#if defined(__mips64)
+# include <sys/procfs.h>
+#endif
#include <sys/user.h>
#include <sys/ustat.h>
#include <linux/cyclades.h>
@@ -284,14 +289,19 @@ namespace __sanitizer {
#endif
#if SANITIZER_LINUX && !SANITIZER_ANDROID && \
- (defined(__i386) || defined(__x86_64))
+ (defined(__i386) || defined(__x86_64) || defined(__mips64))
+#if defined(__mips64)
+ unsigned struct_user_regs_struct_sz = sizeof(struct pt_regs);
+ unsigned struct_user_fpregs_struct_sz = sizeof(elf_fpregset_t);
+#else
unsigned struct_user_regs_struct_sz = sizeof(struct user_regs_struct);
unsigned struct_user_fpregs_struct_sz = sizeof(struct user_fpregs_struct);
-#ifdef __x86_64
+#endif // __mips64
+#if (defined(__x86_64) || defined(__mips64))
unsigned struct_user_fpxregs_struct_sz = 0;
#else
unsigned struct_user_fpxregs_struct_sz = sizeof(struct user_fpxregs_struct);
-#endif
+#endif // __x86_64 || __mips64
int ptrace_peektext = PTRACE_PEEKTEXT;
int ptrace_peekdata = PTRACE_PEEKDATA;
diff --git a/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/lib/sanitizer_common/sanitizer_platform_limits_posix.h
index d375e01a20e4..bd20bea94e93 100644
--- a/lib/sanitizer_common/sanitizer_platform_limits_posix.h
+++ b/lib/sanitizer_common/sanitizer_platform_limits_posix.h
@@ -547,6 +547,10 @@ namespace __sanitizer {
#if SANITIZER_FREEBSD
typedef __sanitizer_sigset_t __sanitizer_kernel_sigset_t;
+#elif defined(__mips__)
+ struct __sanitizer_kernel_sigset_t {
+ u8 sig[16];
+ };
#else
struct __sanitizer_kernel_sigset_t {
u8 sig[8];
@@ -695,7 +699,7 @@ namespace __sanitizer {
#endif
#if SANITIZER_LINUX && !SANITIZER_ANDROID && \
- (defined(__i386) || defined(__x86_64))
+ (defined(__i386) || defined(__x86_64) || defined(__mips64))
extern unsigned struct_user_regs_struct_sz;
extern unsigned struct_user_fpregs_struct_sz;
extern unsigned struct_user_fpxregs_struct_sz;
diff --git a/lib/sanitizer_common/sanitizer_posix.cc b/lib/sanitizer_common/sanitizer_posix.cc
index 6cb51efce2d1..5bc41c2580fb 100644
--- a/lib/sanitizer_common/sanitizer_posix.cc
+++ b/lib/sanitizer_common/sanitizer_posix.cc
@@ -30,6 +30,13 @@
#include <sys/personality.h>
#endif
+#if SANITIZER_FREEBSD
+// The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before
+// that, it was never implemented. So just define it to zero.
+#undef MAP_NORESERVE
+#define MAP_NORESERVE 0
+#endif
+
namespace __sanitizer {
// ------------- sanitizer_common.h
diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
index d20b52483a91..ad20e39556d8 100644
--- a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
@@ -14,7 +14,7 @@
#include "sanitizer_platform.h"
-#if SANITIZER_LINUX && defined(__x86_64__)
+#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__))
#include "sanitizer_stoptheworld.h"
@@ -89,36 +89,50 @@ class ThreadSuspender {
bool SuspendThread(SuspendedThreadID thread_id);
};
-bool ThreadSuspender::SuspendThread(SuspendedThreadID thread_id) {
+bool ThreadSuspender::SuspendThread(SuspendedThreadID tid) {
// Are we already attached to this thread?
// Currently this check takes linear time, however the number of threads is
// usually small.
- if (suspended_threads_list_.Contains(thread_id))
+ if (suspended_threads_list_.Contains(tid))
return false;
int pterrno;
- if (internal_iserror(internal_ptrace(PTRACE_ATTACH, thread_id, NULL, NULL),
+ if (internal_iserror(internal_ptrace(PTRACE_ATTACH, tid, NULL, NULL),
&pterrno)) {
// Either the thread is dead, or something prevented us from attaching.
// Log this event and move on.
- VReport(1, "Could not attach to thread %d (errno %d).\n", thread_id,
- pterrno);
+ VReport(1, "Could not attach to thread %d (errno %d).\n", tid, pterrno);
return false;
} else {
- VReport(1, "Attached to thread %d.\n", thread_id);
+ VReport(1, "Attached to thread %d.\n", tid);
// The thread is not guaranteed to stop before ptrace returns, so we must
- // wait on it.
- uptr waitpid_status;
- HANDLE_EINTR(waitpid_status, internal_waitpid(thread_id, NULL, __WALL));
- int wperrno;
- if (internal_iserror(waitpid_status, &wperrno)) {
- // Got a ECHILD error. I don't think this situation is possible, but it
- // doesn't hurt to report it.
- VReport(1, "Waiting on thread %d failed, detaching (errno %d).\n",
- thread_id, wperrno);
- internal_ptrace(PTRACE_DETACH, thread_id, NULL, NULL);
- return false;
+ // wait on it. Note: if the thread receives a signal concurrently,
+ // we can get notification about the signal before notification about stop.
+ // In such case we need to forward the signal to the thread, otherwise
+ // the signal will be missed (as we do PTRACE_DETACH with arg=0) and
+ // any logic relying on signals will break. After forwarding we need to
+ // continue to wait for stopping, because the thread is not stopped yet.
+ // We do ignore delivery of SIGSTOP, because we want to make stop-the-world
+ // as invisible as possible.
+ for (;;) {
+ int status;
+ uptr waitpid_status;
+ HANDLE_EINTR(waitpid_status, internal_waitpid(tid, &status, __WALL));
+ int wperrno;
+ if (internal_iserror(waitpid_status, &wperrno)) {
+ // Got a ECHILD error. I don't think this situation is possible, but it
+ // doesn't hurt to report it.
+ VReport(1, "Waiting on thread %d failed, detaching (errno %d).\n",
+ tid, wperrno);
+ internal_ptrace(PTRACE_DETACH, tid, NULL, NULL);
+ return false;
+ }
+ if (WIFSTOPPED(status) && WSTOPSIG(status) != SIGSTOP) {
+ internal_ptrace(PTRACE_CONT, tid, 0, (void*)(uptr)WSTOPSIG(status));
+ continue;
+ }
+ break;
}
- suspended_threads_list_.Append(thread_id);
+ suspended_threads_list_.Append(tid);
return true;
}
}
@@ -170,10 +184,9 @@ bool ThreadSuspender::SuspendAllThreads() {
// Pointer to the ThreadSuspender instance for use in signal handler.
static ThreadSuspender *thread_suspender_instance = NULL;
-// Signals that should not be blocked (this is used in the parent thread as well
-// as the tracer thread).
-static const int kUnblockedSignals[] = { SIGABRT, SIGILL, SIGFPE, SIGSEGV,
- SIGBUS, SIGXCPU, SIGXFSZ };
+// Synchronous signals that should not be blocked.
+static const int kSyncSignals[] = { SIGABRT, SIGILL, SIGFPE, SIGSEGV, SIGBUS,
+ SIGXCPU, SIGXFSZ };
// Structure for passing arguments into the tracer thread.
struct TracerThreadArgument {
@@ -188,7 +201,7 @@ struct TracerThreadArgument {
static DieCallbackType old_die_callback;
// Signal handler to wake up suspended threads when the tracer thread dies.
-void TracerThreadSignalHandler(int signum, void *siginfo, void *) {
+static void TracerThreadSignalHandler(int signum, void *siginfo, void *) {
if (thread_suspender_instance != NULL) {
if (signum == SIGABRT)
thread_suspender_instance->KillAllThreads();
@@ -228,6 +241,7 @@ static int TracerThread(void* argument) {
tracer_thread_argument->mutex.Lock();
tracer_thread_argument->mutex.Unlock();
+ old_die_callback = GetDieCallback();
SetDieCallback(TracerThreadDieCallback);
ThreadSuspender thread_suspender(internal_getppid());
@@ -242,17 +256,14 @@ static int TracerThread(void* argument) {
handler_stack.ss_size = kHandlerStackSize;
internal_sigaltstack(&handler_stack, NULL);
- // Install our handler for fatal signals. Other signals should be blocked by
- // the mask we inherited from the caller thread.
- for (uptr signal_index = 0; signal_index < ARRAY_SIZE(kUnblockedSignals);
- signal_index++) {
- __sanitizer_sigaction new_sigaction;
- internal_memset(&new_sigaction, 0, sizeof(new_sigaction));
- new_sigaction.sigaction = TracerThreadSignalHandler;
- new_sigaction.sa_flags = SA_ONSTACK | SA_SIGINFO;
- internal_sigfillset(&new_sigaction.sa_mask);
- internal_sigaction_norestorer(kUnblockedSignals[signal_index],
- &new_sigaction, NULL);
+ // Install our handler for synchronous signals. Other signals should be
+ // blocked by the mask we inherited from the parent thread.
+ for (uptr i = 0; i < ARRAY_SIZE(kSyncSignals); i++) {
+ __sanitizer_sigaction act;
+ internal_memset(&act, 0, sizeof(act));
+ act.sigaction = TracerThreadSignalHandler;
+ act.sa_flags = SA_ONSTACK | SA_SIGINFO;
+ internal_sigaction_norestorer(kSyncSignals[i], &act, 0);
}
int exit_code = 0;
@@ -265,9 +276,11 @@ static int TracerThread(void* argument) {
thread_suspender.ResumeAllThreads();
exit_code = 0;
}
+ // Note, this is a bad race. If TracerThreadDieCallback is already started
+ // in another thread and observed that thread_suspender_instance != 0,
+ // it can call KillAllThreads on the destroyed variable.
+ SetDieCallback(old_die_callback);
thread_suspender_instance = NULL;
- handler_stack.ss_flags = SS_DISABLE;
- internal_sigaltstack(&handler_stack, NULL);
return exit_code;
}
@@ -299,53 +312,21 @@ class ScopedStackSpaceWithGuard {
// into globals.
static __sanitizer_sigset_t blocked_sigset;
static __sanitizer_sigset_t old_sigset;
-static __sanitizer_sigaction old_sigactions
- [ARRAY_SIZE(kUnblockedSignals)];
class StopTheWorldScope {
public:
StopTheWorldScope() {
- // Block all signals that can be blocked safely, and install
- // default handlers for the remaining signals.
- // We cannot allow user-defined handlers to run while the ThreadSuspender
- // thread is active, because they could conceivably call some libc functions
- // which modify errno (which is shared between the two threads).
- internal_sigfillset(&blocked_sigset);
- for (uptr signal_index = 0; signal_index < ARRAY_SIZE(kUnblockedSignals);
- signal_index++) {
- // Remove the signal from the set of blocked signals.
- internal_sigdelset(&blocked_sigset, kUnblockedSignals[signal_index]);
- // Install the default handler.
- __sanitizer_sigaction new_sigaction;
- internal_memset(&new_sigaction, 0, sizeof(new_sigaction));
- new_sigaction.handler = SIG_DFL;
- internal_sigfillset(&new_sigaction.sa_mask);
- internal_sigaction_norestorer(kUnblockedSignals[signal_index],
- &new_sigaction, &old_sigactions[signal_index]);
- }
- int sigprocmask_status =
- internal_sigprocmask(SIG_BLOCK, &blocked_sigset, &old_sigset);
- CHECK_EQ(sigprocmask_status, 0); // sigprocmask should never fail
// Make this process dumpable. Processes that are not dumpable cannot be
// attached to.
process_was_dumpable_ = internal_prctl(PR_GET_DUMPABLE, 0, 0, 0, 0);
if (!process_was_dumpable_)
internal_prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
- old_die_callback = GetDieCallback();
}
~StopTheWorldScope() {
- SetDieCallback(old_die_callback);
// Restore the dumpable flag.
if (!process_was_dumpable_)
internal_prctl(PR_SET_DUMPABLE, 0, 0, 0, 0);
- // Restore the signal handlers.
- for (uptr signal_index = 0; signal_index < ARRAY_SIZE(kUnblockedSignals);
- signal_index++) {
- internal_sigaction_norestorer(kUnblockedSignals[signal_index],
- &old_sigactions[signal_index], NULL);
- }
- internal_sigprocmask(SIG_SETMASK, &old_sigset, &old_sigset);
}
private:
@@ -378,11 +359,36 @@ void StopTheWorld(StopTheWorldCallback callback, void *argument) {
// Block the execution of TracerThread until after we have set ptrace
// permissions.
tracer_thread_argument.mutex.Lock();
+ // Signal handling story.
+ // We don't want async signals to be delivered to the tracer thread,
+ // so we block all async signals before creating the thread. An async signal
+ // handler can temporary modify errno, which is shared with this thread.
+ // We ought to use pthread_sigmask here, because sigprocmask has undefined
+ // behavior in multithreaded programs. However, on linux sigprocmask is
+ // equivalent to pthread_sigmask with the exception that pthread_sigmask
+ // does not allow to block some signals used internally in pthread
+ // implementation. We are fine with blocking them here, we are really not
+ // going to pthread_cancel the thread.
+ // The tracer thread should not raise any synchronous signals. But in case it
+ // does, we setup a special handler for sync signals that properly kills the
+ // parent as well. Note: we don't pass CLONE_SIGHAND to clone, so handlers
+ // in the tracer thread won't interfere with user program. Double note: if a
+ // user does something along the lines of 'kill -11 pid', that can kill the
+ // process even if user setup own handler for SEGV.
+ // Thing to watch out for: this code should not change behavior of user code
+ // in any observable way. In particular it should not override user signal
+ // handlers.
+ internal_sigfillset(&blocked_sigset);
+ for (uptr i = 0; i < ARRAY_SIZE(kSyncSignals); i++)
+ internal_sigdelset(&blocked_sigset, kSyncSignals[i]);
+ int rv = internal_sigprocmask(SIG_BLOCK, &blocked_sigset, &old_sigset);
+ CHECK_EQ(rv, 0);
uptr tracer_pid = internal_clone(
TracerThread, tracer_stack.Bottom(),
CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_UNTRACED,
&tracer_thread_argument, 0 /* parent_tidptr */, 0 /* newtls */, 0
/* child_tidptr */);
+ internal_sigprocmask(SIG_SETMASK, &old_sigset, 0);
int local_errno = 0;
if (internal_iserror(tracer_pid, &local_errno)) {
VReport(1, "Failed spawning a tracer thread (errno %d).\n", local_errno);
@@ -459,4 +465,4 @@ uptr SuspendedThreadsList::RegisterCount() {
}
} // namespace __sanitizer
-#endif // SANITIZER_LINUX && defined(__x86_64__)
+#endif // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__))
diff --git a/lib/sanitizer_common/sanitizer_suppressions.cc b/lib/sanitizer_common/sanitizer_suppressions.cc
index 6b75036c7e50..2b697e955709 100644
--- a/lib/sanitizer_common/sanitizer_suppressions.cc
+++ b/lib/sanitizer_common/sanitizer_suppressions.cc
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// Suppression parsing/matching code shared between TSan and LSan.
+// Suppression parsing/matching code.
//
//===----------------------------------------------------------------------===//
@@ -21,97 +21,43 @@
namespace __sanitizer {
-static const char *const kTypeStrings[SuppressionTypeCount] = {
- "none", "race", "mutex", "thread", "signal", "leak", "called_from_lib",
- "deadlock", "vptr_check", "interceptor_name", "interceptor_via_fun",
- "interceptor_via_lib"};
-
-bool TemplateMatch(char *templ, const char *str) {
- if (str == 0 || str[0] == 0)
- return false;
- bool start = false;
- if (templ && templ[0] == '^') {
- start = true;
- templ++;
- }
- bool asterisk = false;
- while (templ && templ[0]) {
- if (templ[0] == '*') {
- templ++;
- start = false;
- asterisk = true;
- continue;
- }
- if (templ[0] == '$')
- return str[0] == 0 || asterisk;
- if (str[0] == 0)
- return false;
- char *tpos = (char*)internal_strchr(templ, '*');
- char *tpos1 = (char*)internal_strchr(templ, '$');
- if (tpos == 0 || (tpos1 && tpos1 < tpos))
- tpos = tpos1;
- if (tpos != 0)
- tpos[0] = 0;
- const char *str0 = str;
- const char *spos = internal_strstr(str, templ);
- str = spos + internal_strlen(templ);
- templ = tpos;
- if (tpos)
- tpos[0] = tpos == tpos1 ? '$' : '*';
- if (spos == 0)
- return false;
- if (start && spos != str0)
- return false;
- start = false;
- asterisk = false;
- }
- return true;
-}
-
-ALIGNED(64) static char placeholder[sizeof(SuppressionContext)];
-static SuppressionContext *suppression_ctx = 0;
-
-SuppressionContext::SuppressionContext() : suppressions_(1), can_parse_(true) {
- internal_memset(has_suppresson_type_, 0, sizeof(has_suppresson_type_));
-}
-
-SuppressionContext *SuppressionContext::Get() {
- CHECK(suppression_ctx);
- return suppression_ctx;
+SuppressionContext::SuppressionContext(const char *suppression_types[],
+ int suppression_types_num)
+ : suppression_types_(suppression_types),
+ suppression_types_num_(suppression_types_num), suppressions_(1),
+ can_parse_(true) {
+ CHECK_LE(suppression_types_num_, kMaxSuppressionTypes);
+ internal_memset(has_suppression_type_, 0, suppression_types_num_);
}
-void SuppressionContext::InitIfNecessary() {
- if (suppression_ctx)
+void SuppressionContext::ParseFromFile(const char *filename) {
+ if (filename[0] == '\0')
return;
- suppression_ctx = new(placeholder) SuppressionContext;
- if (common_flags()->suppressions[0] == '\0')
- return;
- char *suppressions_from_file;
+ char *file_contents;
uptr buffer_size;
- uptr contents_size =
- ReadFileToBuffer(common_flags()->suppressions, &suppressions_from_file,
- &buffer_size, 1 << 26 /* max_len */);
+ uptr contents_size = ReadFileToBuffer(filename, &file_contents, &buffer_size,
+ 1 << 26 /* max_len */);
if (contents_size == 0) {
Printf("%s: failed to read suppressions file '%s'\n", SanitizerToolName,
- common_flags()->suppressions);
+ filename);
Die();
}
- suppression_ctx->Parse(suppressions_from_file);
+ Parse(file_contents);
}
-bool SuppressionContext::Match(const char *str, SuppressionType type,
+bool SuppressionContext::Match(const char *str, const char *type,
Suppression **s) {
- if (!has_suppresson_type_[type])
- return false;
can_parse_ = false;
- uptr i;
- for (i = 0; i < suppressions_.size(); i++)
- if (type == suppressions_[i].type &&
- TemplateMatch(suppressions_[i].templ, str))
- break;
- if (i == suppressions_.size()) return false;
- *s = &suppressions_[i];
- return true;
+ if (!HasSuppressionType(type))
+ return false;
+ for (uptr i = 0; i < suppressions_.size(); i++) {
+ Suppression &cur = suppressions_[i];
+ if (0 == internal_strcmp(cur.type, type) && TemplateMatch(cur.templ, str)) {
+ *s = &cur;
+ return true;
+ }
+ }
+ return false;
}
static const char *StripPrefix(const char *str, const char *prefix) {
@@ -139,26 +85,26 @@ void SuppressionContext::Parse(const char *str) {
while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t'))
end2--;
int type;
- for (type = 0; type < SuppressionTypeCount; type++) {
- const char *next_char = StripPrefix(line, kTypeStrings[type]);
+ for (type = 0; type < suppression_types_num_; type++) {
+ const char *next_char = StripPrefix(line, suppression_types_[type]);
if (next_char && *next_char == ':') {
line = ++next_char;
break;
}
}
- if (type == SuppressionTypeCount) {
+ if (type == suppression_types_num_) {
Printf("%s: failed to parse suppressions\n", SanitizerToolName);
Die();
}
Suppression s;
- s.type = static_cast<SuppressionType>(type);
+ s.type = suppression_types_[type];
s.templ = (char*)InternalAlloc(end2 - line + 1);
internal_memcpy(s.templ, line, end2 - line);
s.templ[end2 - line] = 0;
s.hit_count = 0;
s.weight = 0;
suppressions_.push_back(s);
- has_suppresson_type_[s.type] = true;
+ has_suppression_type_[type] = true;
}
if (end[0] == 0)
break;
@@ -170,8 +116,12 @@ uptr SuppressionContext::SuppressionCount() const {
return suppressions_.size();
}
-bool SuppressionContext::HasSuppressionType(SuppressionType type) const {
- return has_suppresson_type_[type];
+bool SuppressionContext::HasSuppressionType(const char *type) const {
+ for (int i = 0; i < suppression_types_num_; i++) {
+ if (0 == internal_strcmp(type, suppression_types_[i]))
+ return has_suppression_type_[i];
+ }
+ return false;
}
const Suppression *SuppressionContext::SuppressionAt(uptr i) const {
@@ -186,9 +136,4 @@ void SuppressionContext::GetMatched(
matched->push_back(&suppressions_[i]);
}
-const char *SuppressionTypeString(SuppressionType t) {
- CHECK(t < SuppressionTypeCount);
- return kTypeStrings[t];
-}
-
} // namespace __sanitizer
diff --git a/lib/sanitizer_common/sanitizer_suppressions.h b/lib/sanitizer_common/sanitizer_suppressions.h
index 453731456169..02dbf6f9690b 100644
--- a/lib/sanitizer_common/sanitizer_suppressions.h
+++ b/lib/sanitizer_common/sanitizer_suppressions.h
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// Suppression parsing/matching code shared between TSan and LSan.
+// Suppression parsing/matching code.
//
//===----------------------------------------------------------------------===//
#ifndef SANITIZER_SUPPRESSIONS_H
@@ -18,24 +18,8 @@
namespace __sanitizer {
-enum SuppressionType {
- SuppressionNone,
- SuppressionRace,
- SuppressionMutex,
- SuppressionThread,
- SuppressionSignal,
- SuppressionLeak,
- SuppressionLib,
- SuppressionDeadlock,
- SuppressionVptrCheck,
- SuppressionInterceptorName,
- SuppressionInterceptorViaFunction,
- SuppressionInterceptorViaLibrary,
- SuppressionTypeCount
-};
-
struct Suppression {
- SuppressionType type;
+ const char *type;
char *templ;
unsigned hit_count;
uptr weight;
@@ -43,33 +27,29 @@ struct Suppression {
class SuppressionContext {
public:
+ // Create new SuppressionContext capable of parsing given suppression types.
+ SuppressionContext(const char *supprression_types[],
+ int suppression_types_num);
+
+ void ParseFromFile(const char *filename);
void Parse(const char *str);
- bool Match(const char* str, SuppressionType type, Suppression **s);
+
+ bool Match(const char *str, const char *type, Suppression **s);
uptr SuppressionCount() const;
- bool HasSuppressionType(SuppressionType type) const;
+ bool HasSuppressionType(const char *type) const;
const Suppression *SuppressionAt(uptr i) const;
void GetMatched(InternalMmapVector<Suppression *> *matched);
- // Create a SuppressionContext singleton if it hasn't been created earlier.
- // Not thread safe. Must be called early during initialization (but after
- // runtime flags are parsed).
- static void InitIfNecessary();
- // Returns a SuppressionContext singleton.
- static SuppressionContext *Get();
-
private:
- SuppressionContext();
+ static const int kMaxSuppressionTypes = 16;
+ const char **const suppression_types_;
+ const int suppression_types_num_;
+
InternalMmapVector<Suppression> suppressions_;
- bool has_suppresson_type_[SuppressionTypeCount];
+ bool has_suppression_type_[kMaxSuppressionTypes];
bool can_parse_;
-
- friend class SuppressionContextTest;
};
-const char *SuppressionTypeString(SuppressionType t);
-
-bool TemplateMatch(char *templ, const char *str);
-
} // namespace __sanitizer
#endif // SANITIZER_SUPPRESSIONS_H
diff --git a/lib/sanitizer_common/sanitizer_symbolizer_win.cc b/lib/sanitizer_common/sanitizer_symbolizer_win.cc
index 6bb7d3805604..ed96a3a895a8 100644
--- a/lib/sanitizer_common/sanitizer_symbolizer_win.cc
+++ b/lib/sanitizer_common/sanitizer_symbolizer_win.cc
@@ -30,25 +30,7 @@ class WinSymbolizer : public Symbolizer {
SymbolizedStack *frame = SymbolizedStack::New(addr);
BlockingMutexLock l(&dbghelp_mu_);
- if (!initialized_) {
- if (!TrySymInitialize()) {
- // OK, maybe the client app has called SymInitialize already.
- // That's a bit unfortunate for us as all the DbgHelp functions are
- // single-threaded and we can't coordinate with the app.
- // FIXME: Can we stop the other threads at this point?
- // Anyways, we have to reconfigure stuff to make sure that SymInitialize
- // has all the appropriate options set.
- // Cross our fingers and reinitialize DbgHelp.
- Report("*** WARNING: Failed to initialize DbgHelp! ***\n");
- Report("*** Most likely this means that the app is already ***\n");
- Report("*** using DbgHelp, possibly with incompatible flags. ***\n");
- Report("*** Due to technical reasons, symbolization might crash ***\n");
- Report("*** or produce wrong results. ***\n");
- SymCleanup(GetCurrentProcess());
- TrySymInitialize();
- }
- initialized_ = true;
- }
+ InitializeIfNeeded();
// See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)];
@@ -100,6 +82,58 @@ class WinSymbolizer : public Symbolizer {
// FIXME: Implement GetModuleNameAndOffsetForPC().
private:
+ void InitializeIfNeeded() {
+ if (initialized_)
+ return;
+ if (!TrySymInitialize()) {
+ // OK, maybe the client app has called SymInitialize already.
+ // That's a bit unfortunate for us as all the DbgHelp functions are
+ // single-threaded and we can't coordinate with the app.
+ // FIXME: Can we stop the other threads at this point?
+ // Anyways, we have to reconfigure stuff to make sure that SymInitialize
+ // has all the appropriate options set.
+ // Cross our fingers and reinitialize DbgHelp.
+ Report("*** WARNING: Failed to initialize DbgHelp! ***\n");
+ Report("*** Most likely this means that the app is already ***\n");
+ Report("*** using DbgHelp, possibly with incompatible flags. ***\n");
+ Report("*** Due to technical reasons, symbolization might crash ***\n");
+ Report("*** or produce wrong results. ***\n");
+ SymCleanup(GetCurrentProcess());
+ TrySymInitialize();
+ }
+ initialized_ = true;
+
+ // When an executable is run from a location different from the one where it
+ // was originally built, we may not see the nearby PDB files.
+ // To work around this, let's append the directory of the main module
+ // to the symbol search path. All the failures below are not fatal.
+ const size_t kSymPathSize = 2048;
+ static wchar_t path_buffer[kSymPathSize + 1 + MAX_PATH];
+ if (!SymGetSearchPathW(GetCurrentProcess(), path_buffer, kSymPathSize)) {
+ Report("*** WARNING: Failed to SymGetSearchPathW ***\n");
+ return;
+ }
+ size_t sz = wcslen(path_buffer);
+ if (sz) {
+ CHECK_EQ(0, wcscat_s(path_buffer, L";"));
+ sz++;
+ }
+ DWORD res = GetModuleFileNameW(NULL, path_buffer + sz, MAX_PATH);
+ if (res == 0 || res == MAX_PATH) {
+ Report("*** WARNING: Failed to getting the EXE directory ***\n");
+ return;
+ }
+ // Write the zero character in place of the last backslash to get the
+ // directory of the main module at the end of path_buffer.
+ wchar_t *last_bslash = wcsrchr(path_buffer + sz, L'\\');
+ CHECK_NE(last_bslash, 0);
+ *last_bslash = L'\0';
+ if (!SymSetSearchPathW(GetCurrentProcess(), path_buffer)) {
+ Report("*** WARNING: Failed to SymSetSearchPathW\n");
+ return;
+ }
+ }
+
bool TrySymInitialize() {
SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME | SYMOPT_LOAD_LINES);
return SymInitialize(GetCurrentProcess(), 0, TRUE);
diff --git a/lib/sanitizer_common/sanitizer_syscall_generic.inc b/lib/sanitizer_common/sanitizer_syscall_generic.inc
index 88d237f4e3ce..15cf05f06087 100644
--- a/lib/sanitizer_common/sanitizer_syscall_generic.inc
+++ b/lib/sanitizer_common/sanitizer_syscall_generic.inc
@@ -11,13 +11,13 @@
//
//===----------------------------------------------------------------------===//
-#if SANITIZER_FREEBSD
+#if SANITIZER_FREEBSD || SANITIZER_MAC
# define SYSCALL(name) SYS_ ## name
#else
# define SYSCALL(name) __NR_ ## name
#endif
-#if SANITIZER_FREEBSD && defined(__x86_64__)
+#if (SANITIZER_FREEBSD || SANITIZER_MAC) && defined(__x86_64__)
# define internal_syscall __syscall
# else
# define internal_syscall syscall
diff --git a/lib/sanitizer_common/sanitizer_win.cc b/lib/sanitizer_common/sanitizer_win.cc
index edd4bd11b369..335cecabe118 100644
--- a/lib/sanitizer_common/sanitizer_win.cc
+++ b/lib/sanitizer_common/sanitizer_win.cc
@@ -219,6 +219,7 @@ int CompareModulesBase(const void *pl, const void *pr) {
}
} // namespace
+#ifndef SANITIZER_GO
void DumpProcessMap() {
Report("Dumping process modules:\n");
HANDLE cur_process = GetCurrentProcess();
@@ -263,8 +264,8 @@ void DumpProcessMap() {
for (size_t i = 0; i < num_modules; ++i) {
const ModuleInfo &mi = modules[i];
char module_name[MAX_PATH];
- bool got_module_name = GetModuleFileNameEx(
- cur_process, mi.handle, module_name, sizeof(module_name));
+ bool got_module_name = GetModuleFileNameA(
+ mi.handle, module_name, sizeof(module_name));
if (mi.end_address != 0) {
Printf("\t%p-%p %s\n", mi.base_address, mi.end_address,
got_module_name ? module_name : "[no name]");
@@ -276,6 +277,7 @@ void DumpProcessMap() {
}
UnmapOrDie(modules, num_modules * sizeof(ModuleInfo));
}
+#endif
void DisableCoreDumperIfNecessary() {
// Do nothing.
diff --git a/lib/sanitizer_common/tests/sanitizer_linux_test.cc b/lib/sanitizer_common/tests/sanitizer_linux_test.cc
index 592d9c3eeaf5..11342b775cc7 100644
--- a/lib/sanitizer_common/tests/sanitizer_linux_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_linux_test.cc
@@ -255,6 +255,14 @@ TEST(SanitizerCommon, LibraryNameIs) {
}
}
+#if defined(__mips64)
+// Effectively, this is a test for ThreadDescriptorSize() which is used to
+// compute ThreadSelf().
+TEST(SanitizerLinux, ThreadSelfTest) {
+ ASSERT_EQ(pthread_self(), ThreadSelf());
+}
+#endif
+
} // namespace __sanitizer
#endif // SANITIZER_LINUX
diff --git a/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc b/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
index 0699243283df..e8c30d07e78c 100644
--- a/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
+++ b/lib/sanitizer_common/tests/sanitizer_suppressions_test.cc
@@ -58,117 +58,77 @@ TEST(Suppressions, Match) {
EXPECT_FALSE(MyMatch("foo$^bar", "foobar"));
}
-TEST(Suppressions, TypeStrings) {
- CHECK(!internal_strcmp(SuppressionTypeString(SuppressionNone), "none"));
- CHECK(!internal_strcmp(SuppressionTypeString(SuppressionRace), "race"));
- CHECK(!internal_strcmp(SuppressionTypeString(SuppressionMutex), "mutex"));
- CHECK(!internal_strcmp(SuppressionTypeString(SuppressionThread), "thread"));
- CHECK(!internal_strcmp(SuppressionTypeString(SuppressionSignal), "signal"));
- CHECK(!internal_strcmp(SuppressionTypeString(SuppressionLeak), "leak"));
- CHECK(!internal_strcmp(SuppressionTypeString(SuppressionLib),
- "called_from_lib"));
- CHECK(
- !internal_strcmp(SuppressionTypeString(SuppressionDeadlock), "deadlock"));
- CHECK(!internal_strcmp(SuppressionTypeString(SuppressionVptrCheck),
- "vptr_check"));
- CHECK(!internal_strcmp(SuppressionTypeString(SuppressionInterceptorName),
- "interceptor_name"));
- CHECK(
- !internal_strcmp(SuppressionTypeString(SuppressionInterceptorViaFunction),
- "interceptor_via_fun"));
- CHECK(
- !internal_strcmp(SuppressionTypeString(SuppressionInterceptorViaLibrary),
- "interceptor_via_lib"));
- // Ensure this test is up-to-date when suppression types are added.
- CHECK_EQ(12, SuppressionTypeCount);
-}
+static const char *kTestSuppressionTypes[] = {"race", "thread", "mutex",
+ "signal"};
class SuppressionContextTest : public ::testing::Test {
public:
- virtual void SetUp() { ctx_ = new(placeholder_) SuppressionContext; }
- virtual void TearDown() { ctx_->~SuppressionContext(); }
+ SuppressionContextTest()
+ : ctx_(kTestSuppressionTypes, ARRAY_SIZE(kTestSuppressionTypes)) {}
protected:
- InternalMmapVector<Suppression> *Suppressions() {
- return &ctx_->suppressions_;
+ SuppressionContext ctx_;
+
+ void CheckSuppressions(unsigned count, std::vector<const char *> types,
+ std::vector<const char *> templs) const {
+ EXPECT_EQ(count, ctx_.SuppressionCount());
+ for (unsigned i = 0; i < count; i++) {
+ const Suppression *s = ctx_.SuppressionAt(i);
+ EXPECT_STREQ(types[i], s->type);
+ EXPECT_STREQ(templs[i], s->templ);
+ }
}
- SuppressionContext *ctx_;
- ALIGNED(64) char placeholder_[sizeof(SuppressionContext)];
};
TEST_F(SuppressionContextTest, Parse) {
- ctx_->Parse(
- "race:foo\n"
- " race:bar\n" // NOLINT
- "race:baz \n" // NOLINT
- "# a comment\n"
- "race:quz\n"
- ); // NOLINT
- EXPECT_EQ((unsigned)4, ctx_->SuppressionCount());
- EXPECT_EQ((*Suppressions())[3].type, SuppressionRace);
- EXPECT_EQ(0, strcmp((*Suppressions())[3].templ, "quz"));
- EXPECT_EQ((*Suppressions())[2].type, SuppressionRace);
- EXPECT_EQ(0, strcmp((*Suppressions())[2].templ, "baz"));
- EXPECT_EQ((*Suppressions())[1].type, SuppressionRace);
- EXPECT_EQ(0, strcmp((*Suppressions())[1].templ, "bar"));
- EXPECT_EQ((*Suppressions())[0].type, SuppressionRace);
- EXPECT_EQ(0, strcmp((*Suppressions())[0].templ, "foo"));
+ ctx_.Parse("race:foo\n"
+ " race:bar\n" // NOLINT
+ "race:baz \n" // NOLINT
+ "# a comment\n"
+ "race:quz\n"); // NOLINT
+ CheckSuppressions(4, {"race", "race", "race", "race"},
+ {"foo", "bar", "baz", "quz"});
}
TEST_F(SuppressionContextTest, Parse2) {
- ctx_->Parse(
+ ctx_.Parse(
" # first line comment\n" // NOLINT
" race:bar \n" // NOLINT
"race:baz* *baz\n"
"# a comment\n"
"# last line comment\n"
); // NOLINT
- EXPECT_EQ((unsigned)2, ctx_->SuppressionCount());
- EXPECT_EQ((*Suppressions())[1].type, SuppressionRace);
- EXPECT_EQ(0, strcmp((*Suppressions())[1].templ, "baz* *baz"));
- EXPECT_EQ((*Suppressions())[0].type, SuppressionRace);
- EXPECT_EQ(0, strcmp((*Suppressions())[0].templ, "bar"));
+ CheckSuppressions(2, {"race", "race"}, {"bar", "baz* *baz"});
}
TEST_F(SuppressionContextTest, Parse3) {
- ctx_->Parse(
+ ctx_.Parse(
"# last suppression w/o line-feed\n"
"race:foo\n"
"race:bar"
); // NOLINT
- EXPECT_EQ((unsigned)2, ctx_->SuppressionCount());
- EXPECT_EQ((*Suppressions())[1].type, SuppressionRace);
- EXPECT_EQ(0, strcmp((*Suppressions())[1].templ, "bar"));
- EXPECT_EQ((*Suppressions())[0].type, SuppressionRace);
- EXPECT_EQ(0, strcmp((*Suppressions())[0].templ, "foo"));
+ CheckSuppressions(2, {"race", "race"}, {"foo", "bar"});
}
TEST_F(SuppressionContextTest, ParseType) {
- ctx_->Parse(
+ ctx_.Parse(
"race:foo\n"
"thread:bar\n"
"mutex:baz\n"
"signal:quz\n"
); // NOLINT
- EXPECT_EQ((unsigned)4, ctx_->SuppressionCount());
- EXPECT_EQ((*Suppressions())[3].type, SuppressionSignal);
- EXPECT_EQ(0, strcmp((*Suppressions())[3].templ, "quz"));
- EXPECT_EQ((*Suppressions())[2].type, SuppressionMutex);
- EXPECT_EQ(0, strcmp((*Suppressions())[2].templ, "baz"));
- EXPECT_EQ((*Suppressions())[1].type, SuppressionThread);
- EXPECT_EQ(0, strcmp((*Suppressions())[1].templ, "bar"));
- EXPECT_EQ((*Suppressions())[0].type, SuppressionRace);
- EXPECT_EQ(0, strcmp((*Suppressions())[0].templ, "foo"));
+ CheckSuppressions(4, {"race", "thread", "mutex", "signal"},
+ {"foo", "bar", "baz", "quz"});
}
TEST_F(SuppressionContextTest, HasSuppressionType) {
- ctx_->Parse(
+ ctx_.Parse(
"race:foo\n"
"thread:bar\n");
- EXPECT_TRUE(ctx_->HasSuppressionType(SuppressionRace));
- EXPECT_TRUE(ctx_->HasSuppressionType(SuppressionThread));
- EXPECT_FALSE(ctx_->HasSuppressionType(SuppressionMutex));
- EXPECT_FALSE(ctx_->HasSuppressionType(SuppressionSignal));
+ EXPECT_TRUE(ctx_.HasSuppressionType("race"));
+ EXPECT_TRUE(ctx_.HasSuppressionType("thread"));
+ EXPECT_FALSE(ctx_.HasSuppressionType("mutex"));
+ EXPECT_FALSE(ctx_.HasSuppressionType("signal"));
}
} // namespace __sanitizer