[sanitizer][esan] Add internal_sigaction_syscall
Summary:
Adds a version of sigaction that uses a raw system call, to avoid circular
dependencies and support calling sigaction prior to setting up
interceptors. The new sigaction relies on an assembly sigreturn routine
for its restorer, which is Linux x86_64-only for now.
Uses the new sigaction to initialize the working set tool's shadow fault
handler prior to libc interceptor being set up. This is required to
support instrumentation invoked during interceptor setup, which happens
with an instrumented tcmalloc or other allocator compiled with esan.
Adds a test that emulates an instrumented allocator.
Reviewers: aizatsky
Subscribers: vitalybuka, tberghammer, zhaoqin, danalbert, kcc, srhines, eugenis, llvm-commits, kubabrecka
Differential Revision: http://reviews.llvm.org/D21083
llvm-svn: 272676
diff --git a/compiler-rt/lib/esan/esan.cpp b/compiler-rt/lib/esan/esan.cpp
index e7399e2..e6d6aff 100644
--- a/compiler-rt/lib/esan/esan.cpp
+++ b/compiler-rt/lib/esan/esan.cpp
@@ -197,6 +197,9 @@
}
initializeShadow();
+ if (__esan_which_tool == ESAN_WorkingSet)
+ initializeShadowWorkingSet();
+
initializeInterceptors();
if (__esan_which_tool == ESAN_CacheFrag) {
diff --git a/compiler-rt/lib/esan/esan_interceptors.cpp b/compiler-rt/lib/esan/esan_interceptors.cpp
index 5d4edb5..7aefeb6 100644
--- a/compiler-rt/lib/esan/esan_interceptors.cpp
+++ b/compiler-rt/lib/esan/esan_interceptors.cpp
@@ -17,6 +17,7 @@
#include "interception/interception.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_libc.h"
+#include "sanitizer_common/sanitizer_linux.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
using namespace __esan; // NOLINT
@@ -397,6 +398,11 @@
// This is required to properly use internal_sigaction.
namespace __sanitizer {
int real_sigaction(int signum, const void *act, void *oldact) {
+ if (REAL(sigaction) == nullptr) {
+ // With an instrumented allocator, this is called during interceptor init
+ // and we need a raw syscall solution.
+ return internal_sigaction_syscall(signum, act, oldact);
+ }
return REAL(sigaction)(signum, (const struct sigaction *)act,
(struct sigaction *)oldact);
}
diff --git a/compiler-rt/lib/esan/working_set.cpp b/compiler-rt/lib/esan/working_set.cpp
index 9e7520f..622fd29 100644
--- a/compiler-rt/lib/esan/working_set.cpp
+++ b/compiler-rt/lib/esan/working_set.cpp
@@ -182,10 +182,13 @@
}
}
-void initializeWorkingSet() {
+// Initialization that must be done before any instrumented code is executed.
+void initializeShadowWorkingSet() {
CHECK(getFlags()->cache_line_size == CacheLineSize);
registerMemoryFaultHandler();
+}
+void initializeWorkingSet() {
if (getFlags()->record_snapshots) {
for (u32 i = 0; i < NumFreq; ++i)
SizePerFreq[i].initialize(CircularBufferSizes[i]);
diff --git a/compiler-rt/lib/esan/working_set.h b/compiler-rt/lib/esan/working_set.h
index 3750a48..034dfe6 100644
--- a/compiler-rt/lib/esan/working_set.h
+++ b/compiler-rt/lib/esan/working_set.h
@@ -21,6 +21,7 @@
namespace __esan {
void initializeWorkingSet();
+void initializeShadowWorkingSet();
int finalizeWorkingSet();
void processRangeAccessWorkingSet(uptr PC, uptr Addr, SIZE_T Size,
bool IsWrite);