summaryrefslogtreecommitdiff
path: root/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
diff options
context:
space:
mode:
authorMaxim Ostapenko <chefmax7@gmail.com>2017-04-06 07:42:27 +0000
committerMaxim Ostapenko <chefmax7@gmail.com>2017-04-06 07:42:27 +0000
commit500b2fd06f162094319a95424bcbebf25cd35fd2 (patch)
tree3c2466f5607704a8d360bb656047f93a1d0b86e8 /lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
parent7b9666449c81e5522fd8d32a0e4db368a12e0b41 (diff)
[lsan] Avoid segfaults during threads destruction under high load
This patch addresses two issues: * It turned out that suspended thread may have dtls->dtv_size == kDestroyedThread (-1) and LSan wrongly assumes that DTV is available. This leads to SEGV when LSan tries to iterate through DTV that is invalid. * In some rare cases GetRegistersAndSP can fail with errno 3 (ESRCH). In this case LSan assumes that the whole stack of a given thread is available. This is wrong because ESRCH can indicate that suspended thread was destroyed and its stack was unmapped. This patch properly handles ESRCH from GetRegistersAndSP in order to avoid invalid accesses to already unpapped threads stack. Differential Revision: https://reviews.llvm.org/D30818 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@299630 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc')
-rw-r--r--lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc14
1 files changed, 9 insertions, 5 deletions
diff --git a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
index ce8873b9e..3c0fd7b13 100644
--- a/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
@@ -493,9 +493,9 @@ typedef _user_regs_struct regs_struct;
#error "Unsupported architecture"
#endif // SANITIZER_ANDROID && defined(__arm__)
-int SuspendedThreadsList::GetRegistersAndSP(uptr index,
- uptr *buffer,
- uptr *sp) const {
+PtraceRegistersStatus SuspendedThreadsList::GetRegistersAndSP(uptr index,
+ uptr *buffer,
+ uptr *sp) const {
pid_t tid = GetThreadID(index);
regs_struct regs;
int pterrno;
@@ -513,12 +513,16 @@ int SuspendedThreadsList::GetRegistersAndSP(uptr index,
if (isErr) {
VReport(1, "Could not get registers from thread %d (errno %d).\n", tid,
pterrno);
- return -1;
+ // ESRCH means that the given thread is not suspended or already dead.
+ // Therefore it's unsafe to inspect its data (e.g. walk through stack) and
+ // we should notify caller about this.
+ return pterrno == ESRCH ? REGISTERS_UNAVAILABLE_FATAL
+ : REGISTERS_UNAVAILABLE;
}
*sp = regs.REG_SP;
internal_memcpy(buffer, &regs, sizeof(regs));
- return 0;
+ return REGISTERS_AVAILABLE;
}
uptr SuspendedThreadsList::RegisterCount() {