From efd20cb2f63cf647c7d947d00e8987affefeb177 Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Tue, 28 Feb 2017 16:53:59 -0800 Subject: [PATCH] Catch signals that happen inside a fault handler. Unblock some signals (SIGABRT, SIGBUS, SIGSEGV) that could happen inside of the ART internal fault handlers, to report crashes inside of the signal handler. Because we can't use sigaction to change the handler when this happens, because it modifies global state, add a new member variable in Thread to track whether a call to the fault handler is reentrant or not. Remove the old nested signal implementation that attempted to do this. Bug: http://b/35853436 Test: changed the #if 0 to #if 1, ran a dummy process that threw a NullPointerException, inspected logcat Change-Id: I04bb4a09433c6817933d64ec681ec433b528f2a5 --- runtime/arch/arm/fault_handler_arm.cc | 18 -- runtime/arch/arm64/fault_handler_arm64.cc | 15 -- runtime/arch/mips/fault_handler_mips.cc | 4 - runtime/arch/mips64/fault_handler_mips64.cc | 4 - runtime/arch/x86/fault_handler_x86.cc | 21 -- runtime/arch/x86/quick_entrypoints_x86.S | 13 -- runtime/arch/x86_64/quick_entrypoints_x86_64.S | 12 -- .../entrypoints/quick/quick_throw_entrypoints.cc | 4 - runtime/entrypoints_order_test.cc | 3 +- runtime/fault_handler.cc | 217 +++++++-------------- runtime/fault_handler.h | 1 - runtime/thread.cc | 2 - runtime/thread.h | 22 +-- 13 files changed, 72 insertions(+), 264 deletions(-) diff --git a/runtime/arch/arm/fault_handler_arm.cc b/runtime/arch/arm/fault_handler_arm.cc index daa2dff06..923ff4ff2 100644 --- a/runtime/arch/arm/fault_handler_arm.cc +++ b/runtime/arch/arm/fault_handler_arm.cc @@ -47,24 +47,6 @@ static uint32_t GetInstructionSize(uint8_t* pc) { return instr_size; } -void FaultManager::HandleNestedSignal(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED, - void* context) { - // Note that in this handler we set up the registers and return to - // longjmp directly rather than going through an assembly language stub. The - // reason for this is that longjmp is (currently) in ARM mode and that would - // require switching modes in the stub - incurring an unwanted relocation. - - struct ucontext *uc = reinterpret_cast(context); - struct sigcontext *sc = reinterpret_cast(&uc->uc_mcontext); - Thread* self = Thread::Current(); - CHECK(self != nullptr); // This will cause a SIGABRT if self is null. - - sc->arm_r0 = reinterpret_cast(*self->GetNestedSignalState()); - sc->arm_r1 = 1; - sc->arm_pc = reinterpret_cast(longjmp); - VLOG(signals) << "longjmp address: " << reinterpret_cast(sc->arm_pc); -} - void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo ATTRIBUTE_UNUSED, void* context, ArtMethod** out_method, uintptr_t* out_return_pc, uintptr_t* out_sp) { diff --git a/runtime/arch/arm64/fault_handler_arm64.cc b/runtime/arch/arm64/fault_handler_arm64.cc index c02be87e2..193af58f1 100644 --- a/runtime/arch/arm64/fault_handler_arm64.cc +++ b/runtime/arch/arm64/fault_handler_arm64.cc @@ -39,21 +39,6 @@ extern "C" void art_quick_implicit_suspend(); namespace art { -void FaultManager::HandleNestedSignal(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED, - void* context) { - // To match the case used in ARM we return directly to the longjmp function - // rather than through a trivial assembly language stub. - - struct ucontext *uc = reinterpret_cast(context); - struct sigcontext *sc = reinterpret_cast(&uc->uc_mcontext); - Thread* self = Thread::Current(); - CHECK(self != nullptr); // This will cause a SIGABRT if self is null. - - sc->regs[0] = reinterpret_cast(*self->GetNestedSignalState()); - sc->regs[1] = 1; - sc->pc = reinterpret_cast(longjmp); -} - void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo ATTRIBUTE_UNUSED, void* context, ArtMethod** out_method, uintptr_t* out_return_pc, uintptr_t* out_sp) { diff --git a/runtime/arch/mips/fault_handler_mips.cc b/runtime/arch/mips/fault_handler_mips.cc index 1792f3157..f9c19e87e 100644 --- a/runtime/arch/mips/fault_handler_mips.cc +++ b/runtime/arch/mips/fault_handler_mips.cc @@ -35,10 +35,6 @@ extern "C" void art_quick_throw_null_pointer_exception_from_signal(); namespace art { -void FaultManager::HandleNestedSignal(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED, - void* context ATTRIBUTE_UNUSED) { -} - void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context, ArtMethod** out_method, uintptr_t* out_return_pc, uintptr_t* out_sp) { diff --git a/runtime/arch/mips64/fault_handler_mips64.cc b/runtime/arch/mips64/fault_handler_mips64.cc index 709cab587..d668d3ab6 100644 --- a/runtime/arch/mips64/fault_handler_mips64.cc +++ b/runtime/arch/mips64/fault_handler_mips64.cc @@ -35,10 +35,6 @@ extern "C" void art_quick_throw_null_pointer_exception_from_signal(); namespace art { -void FaultManager::HandleNestedSignal(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED, - void* context ATTRIBUTE_UNUSED) { -} - void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context, ArtMethod** out_method, uintptr_t* out_return_pc, uintptr_t* out_sp) { diff --git a/runtime/arch/x86/fault_handler_x86.cc b/runtime/arch/x86/fault_handler_x86.cc index a4d6bb444..f407ebf1d 100644 --- a/runtime/arch/x86/fault_handler_x86.cc +++ b/runtime/arch/x86/fault_handler_x86.cc @@ -75,12 +75,6 @@ extern "C" void art_quick_throw_null_pointer_exception_from_signal(); extern "C" void art_quick_throw_stack_overflow(); extern "C" void art_quick_test_suspend(); -// Note this is different from the others (no underscore on 64 bit mac) due to -// the way the symbol is defined in the .S file. -// TODO: fix the symbols for 64 bit mac - there is a double underscore prefix for some -// of them. -extern "C" void art_nested_signal_return(); - // Get the size of an instruction in bytes. // Return 0 if the instruction is not handled. static uint32_t GetInstructionSize(const uint8_t* pc) { @@ -247,21 +241,6 @@ static uint32_t GetInstructionSize(const uint8_t* pc) { return pc - startpc; } -void FaultManager::HandleNestedSignal(int, siginfo_t*, void* context) { - // For the Intel architectures we need to go to an assembly language - // stub. This is because the 32 bit call to longjmp is much different - // from the 64 bit ABI call and pushing things onto the stack inside this - // handler was unwieldy and ugly. The use of the stub means we can keep - // this code the same for both 32 and 64 bit. - - Thread* self = Thread::Current(); - CHECK(self != nullptr); // This will cause a SIGABRT if self is null. - - struct ucontext* uc = reinterpret_cast(context); - uc->CTX_JMP_BUF = reinterpret_cast(*self->GetNestedSignalState()); - uc->CTX_EIP = reinterpret_cast(art_nested_signal_return); -} - void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context, ArtMethod** out_method, uintptr_t* out_return_pc, uintptr_t* out_sp) { diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S index 8c907e079..791ec3933 100644 --- a/runtime/arch/x86/quick_entrypoints_x86.S +++ b/runtime/arch/x86/quick_entrypoints_x86.S @@ -2136,19 +2136,6 @@ DEFINE_FUNCTION art_quick_string_compareto ret END_FUNCTION art_quick_string_compareto -// Return from a nested signal: -// Entry: -// eax: address of jmp_buf in TLS - -DEFINE_FUNCTION art_nested_signal_return - SETUP_GOT_NOSAVE ebx // sets %ebx for call into PLT - movl LITERAL(1), %ecx - PUSH ecx // second arg to longjmp (1) - PUSH eax // first arg to longjmp (jmp_buf) - call PLT_SYMBOL(longjmp) - UNREACHABLE -END_FUNCTION art_nested_signal_return - // Create a function `name` calling the ReadBarrier::Mark routine, // getting its argument and returning its result through register // `reg`, saving and restoring all caller-save registers. diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S index f1be52eeb..822b411c1 100644 --- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S +++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S @@ -2099,18 +2099,6 @@ DEFINE_FUNCTION art_quick_instance_of ret END_FUNCTION art_quick_instance_of - -// Return from a nested signal: -// Entry: -// rdi: address of jmp_buf in TLS - -DEFINE_FUNCTION art_nested_signal_return - // first arg to longjmp is already in correct register - movq LITERAL(1), %rsi // second arg to longjmp (1) - call PLT_SYMBOL(longjmp) - UNREACHABLE -END_FUNCTION art_nested_signal_return - // Create a function `name` calling the ReadBarrier::Mark routine, // getting its argument and returning its result through register // `reg`, saving and restoring all caller-save registers. diff --git a/runtime/entrypoints/quick/quick_throw_entrypoints.cc b/runtime/entrypoints/quick/quick_throw_entrypoints.cc index c8ee99a5d..1520e13e4 100644 --- a/runtime/entrypoints/quick/quick_throw_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_throw_entrypoints.cc @@ -62,9 +62,7 @@ extern "C" NO_RETURN void artThrowNullPointerExceptionFromCode(Thread* self) extern "C" NO_RETURN void artThrowNullPointerExceptionFromSignal(uintptr_t addr, Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) { ScopedQuickEntrypointChecks sqec(self); - self->NoteSignalBeingHandled(); ThrowNullPointerExceptionFromDexPC(/* check_address */ true, addr); - self->NoteSignalHandlerDone(); self->QuickDeliverException(); } @@ -95,9 +93,7 @@ extern "C" NO_RETURN void artThrowStringBoundsFromCode(int index, int length, Th extern "C" NO_RETURN void artThrowStackOverflowFromCode(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) { ScopedQuickEntrypointChecks sqec(self); - self->NoteSignalBeingHandled(); ThrowStackOverflowError(self); - self->NoteSignalHandlerDone(); self->QuickDeliverException(); } diff --git a/runtime/entrypoints_order_test.cc b/runtime/entrypoints_order_test.cc index d0687ce7b..55a4625c3 100644 --- a/runtime/entrypoints_order_test.cc +++ b/runtime/entrypoints_order_test.cc @@ -133,9 +133,8 @@ class EntrypointsOrderTest : public CommonRuntimeTest { EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_alloc_stack_top, thread_local_alloc_stack_end, sizeof(void*)); EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_alloc_stack_end, held_mutexes, sizeof(void*)); - EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, held_mutexes, nested_signal_state, + EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, held_mutexes, flip_function, sizeof(void*) * kLockLevelCount); - EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, nested_signal_state, flip_function, sizeof(void*)); EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, flip_function, method_verifier, sizeof(void*)); EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, method_verifier, thread_local_mark_stack, sizeof(void*)); EXPECT_OFFSET_DIFF(Thread, tlsPtr_.thread_local_mark_stack, Thread, wait_mutex_, sizeof(void*), diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc index f9345b64a..64128cc61 100644 --- a/runtime/fault_handler.cc +++ b/runtime/fault_handler.cc @@ -28,47 +28,6 @@ #include "thread-inl.h" #include "verify_object-inl.h" -// Note on nested signal support -// ----------------------------- -// -// Typically a signal handler should not need to deal with signals that occur within it. -// However, when a SIGSEGV occurs that is in generated code and is not one of the -// handled signals (implicit checks), we call a function to try to dump the stack -// to the log. This enhances the debugging experience but may have the side effect -// that it may not work. If the cause of the original SIGSEGV is a corrupted stack or other -// memory region, the stack backtrace code may run into trouble and may either crash -// or fail with an abort (SIGABRT). In either case we don't want that (new) signal to -// mask the original signal and thus prevent useful debug output from being presented. -// -// In order to handle this situation, before we call the stack tracer we do the following: -// -// 1. shutdown the fault manager so that we are talking to the real signal management -// functions rather than those in sigchain. -// 2. use pthread_sigmask to allow SIGSEGV and SIGABRT signals to be delivered to the -// thread running the signal handler. -// 3. set the handler for SIGSEGV and SIGABRT to a secondary signal handler. -// 4. save the thread's state to the TLS of the current thread using 'setjmp' -// -// We then call the stack tracer and one of two things may happen: -// a. it completes successfully -// b. it crashes and a signal is raised. -// -// In the former case, we fall through and everything is fine. In the latter case -// our secondary signal handler gets called in a signal context. This results in -// a call to FaultManager::HandledNestedSignal(), an archirecture specific function -// whose purpose is to call 'longjmp' on the jmp_buf saved in the TLS of the current -// thread. This results in a return with a non-zero value from 'setjmp'. We detect this -// and write something to the log to tell the user that it happened. -// -// Regardless of how we got there, we reach the code after the stack tracer and we -// restore the signal states to their original values, reinstate the fault manager (thus -// reestablishing the signal chain) and continue. - -// This is difficult to test with a runtime test. To invoke the nested signal code -// on any signal, uncomment the following line and run something that throws a -// NullPointerException. -// #define TEST_NESTED_SIGNAL - namespace art { // Static fault manger object accessed by signal handler. FaultManager fault_manager; @@ -83,11 +42,6 @@ static void art_fault_handler(int sig, siginfo_t* info, void* context) { fault_manager.HandleFault(sig, info, context); } -// Signal handler for dealing with a nested signal. -static void art_nested_signal_handler(int sig, siginfo_t* info, void* context) { - fault_manager.HandleNestedSignal(sig, info, context); -} - FaultManager::FaultManager() : initialized_(false) { sigaction(SIGSEGV, nullptr, &oldaction_); } @@ -156,122 +110,93 @@ bool FaultManager::HandleFaultByOtherHandlers(int sig, siginfo_t* info, void* co DCHECK(self != nullptr); DCHECK(Runtime::Current() != nullptr); DCHECK(Runtime::Current()->IsStarted()); - - // Now set up the nested signal handler. - - // TODO: add SIGSEGV back to the nested signals when we can handle running out stack gracefully. - static const int handled_nested_signals[] = {SIGABRT}; - constexpr size_t num_handled_nested_signals = arraysize(handled_nested_signals); - - // Release the fault manager so that it will remove the signal chain for - // SIGSEGV and we call the real sigaction. - fault_manager.Release(); - - // The action for SIGSEGV should be the default handler now. - - // Unblock the signals we allow so that they can be delivered in the signal handler. - sigset_t sigset; - sigemptyset(&sigset); - for (int signal : handled_nested_signals) { - sigaddset(&sigset, signal); + for (const auto& handler : other_handlers_) { + if (handler->Action(sig, info, context)) { + return true; + } } - pthread_sigmask(SIG_UNBLOCK, &sigset, nullptr); + return false; +} - // If we get a signal in this code we want to invoke our nested signal - // handler. - struct sigaction action; - struct sigaction oldactions[num_handled_nested_signals]; - action.sa_sigaction = art_nested_signal_handler; - - // Explicitly mask out SIGSEGV and SIGABRT from the nested signal handler. This - // should be the default but we definitely don't want these happening in our - // nested signal handler. - sigemptyset(&action.sa_mask); - for (int signal : handled_nested_signals) { - sigaddset(&action.sa_mask, signal); +class ScopedSignalUnblocker { + public: + explicit ScopedSignalUnblocker(const std::initializer_list& signals) { + sigset_t new_mask; + sigemptyset(&new_mask); + for (int signal : signals) { + sigaddset(&new_mask, signal); + } + if (sigprocmask(SIG_UNBLOCK, &new_mask, &previous_mask_) != 0) { + PLOG(FATAL) << "failed to unblock signals"; + } } - action.sa_flags = SA_SIGINFO | SA_ONSTACK; -#if !defined(__APPLE__) && !defined(__mips__) - action.sa_restorer = nullptr; -#endif - - // Catch handled signals to invoke our nested handler. - bool success = true; - for (size_t i = 0; i < num_handled_nested_signals; ++i) { - success = sigaction(handled_nested_signals[i], &action, &oldactions[i]) == 0; - if (!success) { - PLOG(ERROR) << "Unable to set up nested signal handler"; - break; + ~ScopedSignalUnblocker() { + if (sigprocmask(SIG_SETMASK, &previous_mask_, nullptr) != 0) { + PLOG(FATAL) << "failed to unblock signals"; } } - if (success) { - // Save the current state and call the handlers. If anything causes a signal - // our nested signal handler will be invoked and this will longjmp to the saved - // state. - if (setjmp(*self->GetNestedSignalState()) == 0) { - for (const auto& handler : other_handlers_) { - if (handler->Action(sig, info, context)) { - // Restore the signal handlers, reinit the fault manager and return. Signal was - // handled. - for (size_t i = 0; i < num_handled_nested_signals; ++i) { - success = sigaction(handled_nested_signals[i], &oldactions[i], nullptr) == 0; - if (!success) { - PLOG(ERROR) << "Unable to restore signal handler"; - } - } - fault_manager.Init(); - return true; - } - } - } else { - LOG(ERROR) << "Nested signal detected - original signal being reported"; - } + private: + sigset_t previous_mask_; +}; - // Restore the signal handlers. - for (size_t i = 0; i < num_handled_nested_signals; ++i) { - success = sigaction(handled_nested_signals[i], &oldactions[i], nullptr) == 0; - if (!success) { - PLOG(ERROR) << "Unable to restore signal handler"; - } - } +class ScopedHandlingSignalSetter { + public: + explicit ScopedHandlingSignalSetter(Thread* thread) : thread_(thread) { + CHECK(!thread->HandlingSignal()); + thread_->SetHandlingSignal(true); } - // Now put the fault manager back in place. - fault_manager.Init(); - return false; -} + ~ScopedHandlingSignalSetter() { + CHECK(thread_->HandlingSignal()); + thread_->SetHandlingSignal(false); + } + + private: + Thread* thread_; +}; void FaultManager::HandleFault(int sig, siginfo_t* info, void* context) { // BE CAREFUL ALLOCATING HERE INCLUDING USING LOG(...) // // If malloc calls abort, it will be holding its lock. // If the handler tries to call malloc, it will deadlock. - VLOG(signals) << "Handling fault"; - if (IsInGeneratedCode(info, context, true)) { - VLOG(signals) << "in generated code, looking for handler"; - for (const auto& handler : generated_code_handlers_) { - VLOG(signals) << "invoking Action on handler " << handler; - if (handler->Action(sig, info, context)) { + + // Use a thread local field to track whether we're recursing, and fall back. + // (e.g.. if one of our handlers crashed) + Thread* thread = Thread::Current(); + + if (thread != nullptr && !thread->HandlingSignal()) { + // Unblock some signals and set thread->handling_signal_ to true, + // so that we can catch crashes in our signal handler. + ScopedHandlingSignalSetter setter(thread); + ScopedSignalUnblocker unblocker { SIGABRT, SIGBUS, SIGSEGV }; // NOLINT + + VLOG(signals) << "Handling fault"; + #ifdef TEST_NESTED_SIGNAL - // In test mode we want to fall through to stack trace handler - // on every signal (in reality this will cause a crash on the first - // signal). - break; -#else - // We have handled a signal so it's time to return from the - // signal handler to the appropriate place. - return; + // Simulate a crash in a handler. + raise(SIGSEGV); #endif + + if (IsInGeneratedCode(info, context, true)) { + VLOG(signals) << "in generated code, looking for handler"; + for (const auto& handler : generated_code_handlers_) { + VLOG(signals) << "invoking Action on handler " << handler; + if (handler->Action(sig, info, context)) { + // We have handled a signal so it's time to return from the + // signal handler to the appropriate place. + return; + } } - } - // We hit a signal we didn't handle. This might be something for which - // we can give more information about so call all registered handlers to see - // if it is. - if (HandleFaultByOtherHandlers(sig, info, context)) { + // We hit a signal we didn't handle. This might be something for which + // we can give more information about so call all registered handlers to + // see if it is. + if (HandleFaultByOtherHandlers(sig, info, context)) { return; + } } } @@ -417,11 +342,7 @@ JavaStackTraceHandler::JavaStackTraceHandler(FaultManager* manager) : FaultHandl bool JavaStackTraceHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* siginfo, void* context) { // Make sure that we are in the generated code, but we may not have a dex pc. -#ifdef TEST_NESTED_SIGNAL - bool in_generated_code = true; -#else bool in_generated_code = manager_->IsInGeneratedCode(siginfo, context, false); -#endif if (in_generated_code) { LOG(ERROR) << "Dumping java stack trace for crash in generated code"; ArtMethod* method = nullptr; @@ -432,12 +353,6 @@ bool JavaStackTraceHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* siginfo, manager_->GetMethodAndReturnPcAndSp(siginfo, context, &method, &return_pc, &sp); // Inside of generated code, sp[0] is the method, so sp is the frame. self->SetTopOfStack(reinterpret_cast(sp)); -#ifdef TEST_NESTED_SIGNAL - // To test the nested signal handler we raise a signal here. This will cause the - // nested signal handler to be called and perform a longjmp back to the setjmp - // above. - abort(); -#endif self->DumpJavaStack(LOG_STREAM(ERROR)); } diff --git a/runtime/fault_handler.h b/runtime/fault_handler.h index 56e0fb78c..ce59ba7e6 100644 --- a/runtime/fault_handler.h +++ b/runtime/fault_handler.h @@ -45,7 +45,6 @@ class FaultManager { void EnsureArtActionInFrontOfSignalChain(); void HandleFault(int sig, siginfo_t* info, void* context); - void HandleNestedSignal(int sig, siginfo_t* info, void* context); // Added handlers are owned by the fault handler and will be freed on Shutdown(). void AddHandler(FaultHandler* handler, bool generated_code); diff --git a/runtime/thread.cc b/runtime/thread.cc index ff66cc169..30a4046d7 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -1934,7 +1934,6 @@ Thread::Thread(bool daemon) wait_cond_ = new ConditionVariable("a thread wait condition variable", *wait_mutex_); tlsPtr_.instrumentation_stack = new std::deque; tlsPtr_.name = new std::string(kThreadNameDuringStartup); - tlsPtr_.nested_signal_state = static_cast(malloc(sizeof(jmp_buf))); static_assert((sizeof(Thread) % 4) == 0U, "art::Thread has a size which is not a multiple of 4."); @@ -2118,7 +2117,6 @@ Thread::~Thread() { delete tlsPtr_.instrumentation_stack; delete tlsPtr_.name; delete tlsPtr_.deps_or_stack_trace_sample.stack_trace_sample; - free(tlsPtr_.nested_signal_state); Runtime::Current()->GetHeap()->AssertThreadLocalBuffersAreRevoked(this); diff --git a/runtime/thread.h b/runtime/thread.h index d5fd9e9e5..de0b892f5 100644 --- a/runtime/thread.h +++ b/runtime/thread.h @@ -1115,21 +1115,12 @@ class Thread { return tlsPtr_.mterp_alt_ibase; } - // Notify that a signal is being handled. This is to protect us from doing recursive - // NPE handling after a SIGSEGV. - void NoteSignalBeingHandled() { - if (tls32_.handling_signal_) { - LOG(FATAL) << "Detected signal while processing a signal"; - } - tls32_.handling_signal_ = true; - } - - void NoteSignalHandlerDone() { - tls32_.handling_signal_ = false; + bool HandlingSignal() const { + return tls32_.handling_signal_; } - jmp_buf* GetNestedSignalState() { - return tlsPtr_.nested_signal_state; + void SetHandlingSignal(bool handling_signal) { + tls32_.handling_signal_ = handling_signal; } bool IsTransitioningToRunnable() const { @@ -1460,7 +1451,7 @@ class Thread { thread_local_start(nullptr), thread_local_pos(nullptr), thread_local_end(nullptr), thread_local_objects(0), mterp_current_ibase(nullptr), mterp_default_ibase(nullptr), mterp_alt_ibase(nullptr), thread_local_alloc_stack_top(nullptr), - thread_local_alloc_stack_end(nullptr), nested_signal_state(nullptr), + thread_local_alloc_stack_end(nullptr), flip_function(nullptr), method_verifier(nullptr), thread_local_mark_stack(nullptr) { std::fill(held_mutexes, held_mutexes + kLockLevelCount, nullptr); } @@ -1606,9 +1597,6 @@ class Thread { // Support for Mutex lock hierarchy bug detection. BaseMutex* held_mutexes[kLockLevelCount]; - // Recorded thread state for nested signals. - jmp_buf* nested_signal_state; - // The function used for thread flip. Closure* flip_function; -- 2.11.0