diff options
author | Dave Allison <dallison@google.com> | 2014-07-10 01:54:57 +0000 |
---|---|---|
committer | Dave Allison <dallison@google.com> | 2014-07-10 01:54:57 +0000 |
commit | 3d14eb620716e92c21c4d2c2d11a95be53319791 (patch) | |
tree | aadce4d6bb70e549b74b537c6f75617cf533576a /runtime | |
parent | 34e826ccc80dc1cf7c4c045de6b7f8360d504ccf (diff) | |
download | art-3d14eb620716e92c21c4d2c2d11a95be53319791.zip art-3d14eb620716e92c21c4d2c2d11a95be53319791.tar.gz art-3d14eb620716e92c21c4d2c2d11a95be53319791.tar.bz2 |
Revert "Add implicit null and stack checks for x86"
It breaks cross compilation with x86_64.
This reverts commit 34e826ccc80dc1cf7c4c045de6b7f8360d504ccf.
Change-Id: I34ba07821fc0a022fda33a7ae21850957bbec5e7
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/Android.mk | 1 | ||||
-rw-r--r-- | runtime/arch/arm/fault_handler_arm.cc | 11 | ||||
-rw-r--r-- | runtime/arch/arm64/fault_handler_arm64.cc | 3 | ||||
-rw-r--r-- | runtime/arch/mips/fault_handler_mips.cc | 3 | ||||
-rw-r--r-- | runtime/arch/x86/fault_handler_x86.cc | 285 | ||||
-rw-r--r-- | runtime/arch/x86/quick_entrypoints_x86.S | 15 | ||||
-rw-r--r-- | runtime/arch/x86_64/fault_handler_x86_64.cc | 3 | ||||
-rw-r--r-- | runtime/fault_handler.cc | 31 | ||||
-rw-r--r-- | runtime/fault_handler.h | 5 | ||||
-rw-r--r-- | runtime/parsed_options.cc | 5 | ||||
-rw-r--r-- | runtime/runtime.cc | 61 | ||||
-rw-r--r-- | runtime/thread.cc | 90 | ||||
-rw-r--r-- | runtime/thread_linux.cc | 6 |
13 files changed, 81 insertions, 438 deletions
diff --git a/runtime/Android.mk b/runtime/Android.mk index 3774b32..7f5cf0c 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -412,7 +412,6 @@ $$(ENUM_OPERATOR_OUT_GEN): $$(GENERATED_SRC_DIR)/%_operator_out.cc : $(LOCAL_PAT LOCAL_STATIC_LIBRARIES := libziparchive libz else # host LOCAL_STATIC_LIBRARIES += libcutils libziparchive-host libz libutils - LOCAL_SHARED_LIBRARIES += libsigchain LOCAL_LDLIBS += -ldl -lpthread ifeq ($$(HOST_OS),linux) LOCAL_LDLIBS += -lrt diff --git a/runtime/arch/arm/fault_handler_arm.cc b/runtime/arch/arm/fault_handler_arm.cc index e22c56e..2a82129 100644 --- a/runtime/arch/arm/fault_handler_arm.cc +++ b/runtime/arch/arm/fault_handler_arm.cc @@ -46,10 +46,9 @@ static uint32_t GetInstructionSize(uint8_t* pc) { return instr_size; } -void FaultManager::GetMethodAndReturnPCAndSP(siginfo_t* siginfo, void* context, - mirror::ArtMethod** out_method, +void FaultManager::GetMethodAndReturnPCAndSP(void* context, mirror::ArtMethod** out_method, uintptr_t* out_return_pc, uintptr_t* out_sp) { - struct ucontext* uc = reinterpret_cast<struct ucontext*>(context); + struct ucontext *uc = (struct ucontext *)context; struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext); *out_sp = static_cast<uintptr_t>(sc->arm_sp); VLOG(signals) << "sp: " << *out_sp; @@ -115,7 +114,7 @@ bool SuspensionHandler::Action(int sig, siginfo_t* info, void* context) { uint32_t checkinst1 = 0xf8d90000 + Thread::ThreadSuspendTriggerOffset<4>().Int32Value(); uint16_t checkinst2 = 0x6800; - struct ucontext* uc = reinterpret_cast<struct ucontext*>(context); + struct ucontext *uc = (struct ucontext *)context; struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext); uint8_t* ptr2 = reinterpret_cast<uint8_t*>(sc->arm_pc); uint8_t* ptr1 = ptr2 - 4; @@ -179,7 +178,7 @@ bool SuspensionHandler::Action(int sig, siginfo_t* info, void* context) { // to the overflow region below the protected region. bool StackOverflowHandler::Action(int sig, siginfo_t* info, void* context) { - struct ucontext* uc = reinterpret_cast<struct ucontext*>(context); + struct ucontext *uc = (struct ucontext *)context; struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext); VLOG(signals) << "stack overflow handler with sp at " << std::hex << &uc; VLOG(signals) << "sigcontext: " << std::hex << sc; @@ -206,7 +205,7 @@ bool StackOverflowHandler::Action(int sig, siginfo_t* info, void* context) { } // We know this is a stack overflow. We need to move the sp to the overflow region - // that exists below the protected region. Determine the address of the next + // the exists below the protected region. Determine the address of the next // available valid address below the protected region. uintptr_t prevsp = sp; sp = pregion; diff --git a/runtime/arch/arm64/fault_handler_arm64.cc b/runtime/arch/arm64/fault_handler_arm64.cc index 34eede6..74c3023 100644 --- a/runtime/arch/arm64/fault_handler_arm64.cc +++ b/runtime/arch/arm64/fault_handler_arm64.cc @@ -29,8 +29,7 @@ namespace art { -void FaultManager::GetMethodAndReturnPCAndSP(siginfo_t* siginfo, void* context, - mirror::ArtMethod** out_method, +void FaultManager::GetMethodAndReturnPCAndSP(void* context, mirror::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 5a64a69..1ecd7d9 100644 --- a/runtime/arch/mips/fault_handler_mips.cc +++ b/runtime/arch/mips/fault_handler_mips.cc @@ -29,8 +29,7 @@ namespace art { -void FaultManager::GetMethodAndReturnPCAndSP(siginfo_t* siginfo, void* context, - mirror::ArtMethod** out_method, +void FaultManager::GetMethodAndReturnPCAndSP(void* context, mirror::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 f62200a..7c1980e 100644 --- a/runtime/arch/x86/fault_handler_x86.cc +++ b/runtime/arch/x86/fault_handler_x86.cc @@ -21,10 +21,6 @@ #include "globals.h" #include "base/logging.h" #include "base/hex_dump.h" -#include "mirror/art_method.h" -#include "mirror/art_method-inl.h" -#include "thread.h" -#include "thread-inl.h" // @@ -33,294 +29,19 @@ namespace art { -extern "C" void art_quick_throw_null_pointer_exception(); -extern "C" void art_quick_throw_stack_overflow_from_signal(); -extern "C" void art_quick_test_suspend(); - -// From the x86 disassembler... -enum SegmentPrefix { - kCs = 0x2e, - kSs = 0x36, - kDs = 0x3e, - kEs = 0x26, - kFs = 0x64, - kGs = 0x65, -}; - -// Get the size of an instruction in bytes. -static uint32_t GetInstructionSize(uint8_t* pc) { - uint8_t* instruction_start = pc; - bool have_prefixes = true; - bool two_byte = false; - - // Skip all the prefixes. - do { - switch (*pc) { - // Group 1 - lock and repeat prefixes: - case 0xF0: - case 0xF2: - case 0xF3: - // Group 2 - segment override prefixes: - case kCs: - case kSs: - case kDs: - case kEs: - case kFs: - case kGs: - // Group 3 - operand size override: - case 0x66: - // Group 4 - address size override: - case 0x67: - break; - default: - have_prefixes = false; - break; - } - if (have_prefixes) { - pc++; - } - } while (have_prefixes); - -#if defined(__x86_64__) - // Skip REX is present. - if (*pc >= 0x40 && *pc <= 0x4F) { - ++pc; - } -#endif - - // Check for known instructions. - uint32_t known_length = 0; - switch (*pc) { - case 0x83: // cmp [r + v], b: 4 byte instruction - known_length = 4; - break; - } - - if (known_length > 0) { - VLOG(signals) << "known instruction with length " << known_length; - return known_length; - } - - // Unknown instruction, work out length. - - // Work out if we have a ModR/M byte. - uint8_t opcode = *pc++; - if (opcode == 0xf) { - two_byte = true; - opcode = *pc++; - } - - bool has_modrm = false; // Is ModR/M byte present? - uint8_t hi = opcode >> 4; // Opcode high nybble. - uint8_t lo = opcode & 0b1111; // Opcode low nybble. - - // From the Intel opcode tables. - if (two_byte) { - has_modrm = true; // TODO: all of these? - } else if (hi < 4) { - has_modrm = lo < 4 || (lo >= 8 && lo <= 0xb); - } else if (hi == 6) { - has_modrm = lo == 3 || lo == 9 || lo == 0xb; - } else if (hi == 8) { - has_modrm = lo != 0xd; - } else if (hi == 0xc) { - has_modrm = lo == 1 || lo == 2 || lo == 6 || lo == 7; - } else if (hi == 0xd) { - has_modrm = lo < 4; - } else if (hi == 0xf) { - has_modrm = lo == 6 || lo == 7; - } - - if (has_modrm) { - uint8_t modrm = *pc++; - uint8_t mod = (modrm >> 6) & 0b11; - uint8_t reg = (modrm >> 3) & 0b111; - switch (mod) { - case 0: - break; - case 1: - if (reg == 4) { - // SIB + 1 byte displacement. - pc += 2; - } else { - pc += 1; - } - break; - case 2: - // SIB + 4 byte displacement. - pc += 5; - break; - case 3: - break; - } - } - - VLOG(signals) << "calculated X86 instruction size is " << (pc - instruction_start); - return pc - instruction_start; -} - -void FaultManager::GetMethodAndReturnPCAndSP(siginfo_t* siginfo, void* context, - mirror::ArtMethod** out_method, +void FaultManager::GetMethodAndReturnPCAndSP(void* context, mirror::ArtMethod** out_method, uintptr_t* out_return_pc, uintptr_t* out_sp) { - struct ucontext* uc = reinterpret_cast<struct ucontext*>(context); - *out_sp = static_cast<uintptr_t>(uc->uc_mcontext.gregs[REG_ESP]); - VLOG(signals) << "sp: " << std::hex << *out_sp; - if (*out_sp == 0) { - return; - } - - // In the case of a stack overflow, the stack is not valid and we can't - // get the method from the top of the stack. However it's in EAX. - uintptr_t* fault_addr = reinterpret_cast<uintptr_t*>(siginfo->si_addr); - uintptr_t* overflow_addr = reinterpret_cast<uintptr_t*>( - reinterpret_cast<uint8_t*>(*out_sp) - GetStackOverflowReservedBytes(kX86)); - if (overflow_addr == fault_addr) { - *out_method = reinterpret_cast<mirror::ArtMethod*>(uc->uc_mcontext.gregs[REG_EAX]); - } else { - // The method is at the top of the stack. - *out_method = reinterpret_cast<mirror::ArtMethod*>(reinterpret_cast<uintptr_t*>(*out_sp)[0]); - } - - uint8_t* pc = reinterpret_cast<uint8_t*>(uc->uc_mcontext.gregs[REG_EIP]); - VLOG(signals) << HexDump(pc, 32, true, "PC "); - - uint32_t instr_size = GetInstructionSize(pc); - *out_return_pc = reinterpret_cast<uintptr_t>(pc + instr_size); } bool NullPointerHandler::Action(int sig, siginfo_t* info, void* context) { - struct ucontext *uc = reinterpret_cast<struct ucontext*>(context); - uint8_t* pc = reinterpret_cast<uint8_t*>(uc->uc_mcontext.gregs[REG_EIP]); - uint8_t* sp = reinterpret_cast<uint8_t*>(uc->uc_mcontext.gregs[REG_ESP]); - - uint32_t instr_size = GetInstructionSize(pc); - // We need to arrange for the signal handler to return to the null pointer - // exception generator. The return address must be the address of the - // next instruction (this instruction + instruction size). The return address - // is on the stack at the top address of the current frame. - - // Push the return address onto the stack. - uint32_t retaddr = reinterpret_cast<uint32_t>(pc + instr_size); - uint32_t* next_sp = reinterpret_cast<uint32_t*>(sp - 4); - *next_sp = retaddr; - uc->uc_mcontext.gregs[REG_ESP] = reinterpret_cast<uint32_t>(next_sp); - - uc->uc_mcontext.gregs[REG_EIP] = - reinterpret_cast<uintptr_t>(art_quick_throw_null_pointer_exception); - VLOG(signals) << "Generating null pointer exception"; - return true; + return false; } -// A suspend check is done using the following instruction sequence: -// 0xf720f1df: 648B058C000000 mov eax, fs:[0x8c] ; suspend_trigger -// .. some intervening instructions. -// 0xf720f1e6: 8500 test eax, [eax] - -// The offset from fs is Thread::ThreadSuspendTriggerOffset(). -// To check for a suspend check, we examine the instructions that caused -// the fault. bool SuspensionHandler::Action(int sig, siginfo_t* info, void* context) { - // These are the instructions to check for. The first one is the mov eax, fs:[xxx] - // where xxx is the offset of the suspend trigger. - uint32_t trigger = Thread::ThreadSuspendTriggerOffset<4>().Int32Value(); - - VLOG(signals) << "Checking for suspension point"; - uint8_t checkinst1[] = {0x64, 0x8b, 0x05, static_cast<uint8_t>(trigger & 0xff), - static_cast<uint8_t>((trigger >> 8) & 0xff), 0, 0}; - uint8_t checkinst2[] = {0x85, 0x00}; - - struct ucontext *uc = reinterpret_cast<struct ucontext*>(context); - uint8_t* pc = reinterpret_cast<uint8_t*>(uc->uc_mcontext.gregs[REG_EIP]); - uint8_t* sp = reinterpret_cast<uint8_t*>(uc->uc_mcontext.gregs[REG_ESP]); - - if (pc[0] != checkinst2[0] || pc[1] != checkinst2[1]) { - // Second instruction is not correct (test eax,[eax]). - VLOG(signals) << "Not a suspension point"; - return false; - } - - // The first instruction can a little bit up the stream due to load hoisting - // in the compiler. - uint8_t* limit = pc - 100; // Compiler will hoist to a max of 20 instructions. - uint8_t* ptr = pc - sizeof(checkinst1); - bool found = false; - while (ptr > limit) { - if (memcmp(ptr, checkinst1, sizeof(checkinst1)) == 0) { - found = true; - break; - } - ptr -= 1; - } - - if (found) { - VLOG(signals) << "suspend check match"; - - // We need to arrange for the signal handler to return to the null pointer - // exception generator. The return address must be the address of the - // next instruction (this instruction + 2). The return address - // is on the stack at the top address of the current frame. - - // Push the return address onto the stack. - uint32_t retaddr = reinterpret_cast<uint32_t>(pc + 2); - uint32_t* next_sp = reinterpret_cast<uint32_t*>(sp - 4); - *next_sp = retaddr; - uc->uc_mcontext.gregs[REG_ESP] = reinterpret_cast<uint32_t>(next_sp); - - uc->uc_mcontext.gregs[REG_EIP] = reinterpret_cast<uintptr_t>(art_quick_test_suspend); - - // Now remove the suspend trigger that caused this fault. - Thread::Current()->RemoveSuspendTrigger(); - VLOG(signals) << "removed suspend trigger invoking test suspend"; - return true; - } - VLOG(signals) << "Not a suspend check match, first instruction mismatch"; return false; } -// The stack overflow check is done using the following instruction: -// test eax, [esp+ -xxx] -// where 'xxx' is the size of the overflow area. -// -// This is done before any frame is established in the method. The return -// address for the previous method is on the stack at ESP. - bool StackOverflowHandler::Action(int sig, siginfo_t* info, void* context) { - struct ucontext *uc = reinterpret_cast<struct ucontext*>(context); - uintptr_t sp = static_cast<uintptr_t>(uc->uc_mcontext.gregs[REG_ESP]); - - uintptr_t fault_addr = reinterpret_cast<uintptr_t>(info->si_addr); - VLOG(signals) << "fault_addr: " << std::hex << fault_addr; - VLOG(signals) << "checking for stack overflow, sp: " << std::hex << sp << - ", fault_addr: " << fault_addr; - - uintptr_t overflow_addr = sp - GetStackOverflowReservedBytes(kX86); - - Thread* self = Thread::Current(); - uintptr_t pregion = reinterpret_cast<uintptr_t>(self->GetStackEnd()) - - Thread::kStackOverflowProtectedSize; - - // Check that the fault address is the value expected for a stack overflow. - if (fault_addr != overflow_addr) { - VLOG(signals) << "Not a stack overflow"; - return false; - } - - // We know this is a stack overflow. We need to move the sp to the overflow region - // that exists below the protected region. Determine the address of the next - // available valid address below the protected region. - VLOG(signals) << "setting sp to overflow region at " << std::hex << pregion; - - // Since the compiler puts the implicit overflow - // check before the callee save instructions, the SP is already pointing to - // the previous frame. - - // Tell the stack overflow code where the new stack pointer should be. - uc->uc_mcontext.gregs[REG_EAX] = pregion; - - // Now arrange for the signal handler to return to art_quick_throw_stack_overflow_from_signal. - uc->uc_mcontext.gregs[REG_EIP] = reinterpret_cast<uintptr_t>( - art_quick_throw_stack_overflow_from_signal); - - return true; + return false; } } // namespace art diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S index 68f46ad..24b9e46 100644 --- a/runtime/arch/x86/quick_entrypoints_x86.S +++ b/runtime/arch/x86/quick_entrypoints_x86.S @@ -173,21 +173,6 @@ NO_ARG_RUNTIME_EXCEPTION art_quick_throw_div_zero, artThrowDivZeroFromCode */ NO_ARG_RUNTIME_EXCEPTION art_quick_throw_stack_overflow, artThrowStackOverflowFromCode -// On entry to this function, EAX contains the ESP value for the overflow region. -DEFINE_FUNCTION art_quick_throw_stack_overflow_from_signal - // Here, the ESP is above the protected region. We need to create a - // callee save frame and then move ESP down to the overflow region. - SETUP_SAVE_ALL_CALLEE_SAVE_FRAME // save all registers as basis for long jump context - mov %esp, %ecx // get current stack pointer - mov %eax, %esp // move ESP to the overflow region. - PUSH ecx // pass SP - pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current() - CFI_ADJUST_CFA_OFFSET(4) - SETUP_GOT_NOSAVE // clobbers ebx (harmless here) - call PLT_SYMBOL(artThrowStackOverflowFromCode) // artThrowStackOverflowFromCode(Thread*, SP) - int3 // unreached -END_FUNCTION art_quick_throw_stack_overflow_from_signal - /* * Called by managed code, saves callee saves and then calls artThrowException * that will place a mock Method* at the bottom of the stack. Arg1 holds the exception. diff --git a/runtime/arch/x86_64/fault_handler_x86_64.cc b/runtime/arch/x86_64/fault_handler_x86_64.cc index 88ae7f3..233d3c7 100644 --- a/runtime/arch/x86_64/fault_handler_x86_64.cc +++ b/runtime/arch/x86_64/fault_handler_x86_64.cc @@ -29,8 +29,7 @@ namespace art { -void FaultManager::GetMethodAndReturnPCAndSP(siginfo_t* siginfo, void* context, - mirror::ArtMethod** out_method, +void FaultManager::GetMethodAndReturnPCAndSP(void* context, mirror::ArtMethod** out_method, uintptr_t* out_return_pc, uintptr_t* out_sp) { } diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc index f99ce07..3112bc0 100644 --- a/runtime/fault_handler.cc +++ b/runtime/fault_handler.cc @@ -29,7 +29,9 @@ #include "mirror/object-inl.h" #include "object_utils.h" #include "scoped_thread_state_change.h" +#ifdef HAVE_ANDROID_OS #include "sigchain.h" +#endif #include "verify_object-inl.h" namespace art { @@ -45,7 +47,6 @@ void art_sigsegv_fault() { // Signal handler called on SIGSEGV. static void art_fault_handler(int sig, siginfo_t* info, void* context) { - // std::cout << "handling fault in ART handler\n"; fault_manager.HandleFault(sig, info, context); } @@ -54,7 +55,9 @@ FaultManager::FaultManager() { } FaultManager::~FaultManager() { +#ifdef HAVE_ANDROID_OS UnclaimSignalChain(SIGSEGV); +#endif sigaction(SIGSEGV, &oldaction_, nullptr); // Restore old handler. } @@ -69,12 +72,11 @@ void FaultManager::Init() { #endif // Set our signal handler now. - int e = sigaction(SIGSEGV, &action, &oldaction_); - if (e != 0) { - VLOG(signals) << "Failed to claim SEGV: " << strerror(errno); - } + sigaction(SIGSEGV, &action, &oldaction_); +#ifdef HAVE_ANDROID_OS // Make sure our signal handler is called before any user handlers. ClaimSignalChain(SIGSEGV, &oldaction_); +#endif } void FaultManager::HandleFault(int sig, siginfo_t* info, void* context) { @@ -82,12 +84,8 @@ void FaultManager::HandleFault(int sig, siginfo_t* info, void* context) { // // If malloc calls abort, it will be holding its lock. // If the handler tries to call malloc, it will deadlock. - - // Also, there is only an 8K stack available here to logging can cause memory - // overwrite issues if you are unlucky. If you want to enable logging and - // are getting crashes, allocate more space for the alternate signal stack. VLOG(signals) << "Handling fault"; - if (IsInGeneratedCode(info, context, true)) { + if (IsInGeneratedCode(context, true)) { VLOG(signals) << "in generated code, looking for handler"; for (const auto& handler : generated_code_handlers_) { VLOG(signals) << "invoking Action on handler " << handler; @@ -103,8 +101,11 @@ void FaultManager::HandleFault(int sig, siginfo_t* info, void* context) { } art_sigsegv_fault(); - // Pass this on to the next handler in the chain, or the default if none. +#ifdef HAVE_ANDROID_OS InvokeUserSignalHandler(sig, info, context); +#else + oldaction_.sa_sigaction(sig, info, context); +#endif } void FaultManager::AddHandler(FaultHandler* handler, bool generated_code) { @@ -131,7 +132,7 @@ void FaultManager::RemoveHandler(FaultHandler* handler) { // This function is called within the signal handler. It checks that // the mutator_lock is held (shared). No annotalysis is done. -bool FaultManager::IsInGeneratedCode(siginfo_t* siginfo, void* context, bool check_dex_pc) { +bool FaultManager::IsInGeneratedCode(void* context, bool check_dex_pc) { // We can only be running Java code in the current thread if it // is in Runnable state. VLOG(signals) << "Checking for generated code"; @@ -160,7 +161,7 @@ bool FaultManager::IsInGeneratedCode(siginfo_t* siginfo, void* context, bool che // Get the architecture specific method address and return address. These // are in architecture specific files in arch/<arch>/fault_handler_<arch>. - GetMethodAndReturnPCAndSP(siginfo, context, &method_obj, &return_pc, &sp); + GetMethodAndReturnPCAndSP(context, &method_obj, &return_pc, &sp); // If we don't have a potential method, we're outta here. VLOG(signals) << "potential method: " << method_obj; @@ -241,12 +242,12 @@ JavaStackTraceHandler::JavaStackTraceHandler(FaultManager* manager) : FaultHandl bool JavaStackTraceHandler::Action(int sig, siginfo_t* siginfo, void* context) { // Make sure that we are in the generated code, but we may not have a dex pc. - if (manager_->IsInGeneratedCode(siginfo, context, false)) { + if (manager_->IsInGeneratedCode(context, false)) { LOG(ERROR) << "Dumping java stack trace for crash in generated code"; mirror::ArtMethod* method = nullptr; uintptr_t return_pc = 0; uintptr_t sp = 0; - manager_->GetMethodAndReturnPCAndSP(siginfo, context, &method, &return_pc, &sp); + manager_->GetMethodAndReturnPCAndSP(context, &method, &return_pc, &sp); Thread* self = Thread::Current(); // Inside of generated code, sp[0] is the method, so sp is the frame. StackReference<mirror::ArtMethod>* frame = diff --git a/runtime/fault_handler.h b/runtime/fault_handler.h index 71c9977..026f5b9 100644 --- a/runtime/fault_handler.h +++ b/runtime/fault_handler.h @@ -43,10 +43,9 @@ class FaultManager { void HandleFault(int sig, siginfo_t* info, void* context); void AddHandler(FaultHandler* handler, bool generated_code); void RemoveHandler(FaultHandler* handler); - void GetMethodAndReturnPCAndSP(siginfo_t* siginfo, void* context, mirror::ArtMethod** out_method, + void GetMethodAndReturnPCAndSP(void* context, mirror::ArtMethod** out_method, uintptr_t* out_return_pc, uintptr_t* out_sp); - bool IsInGeneratedCode(siginfo_t* siginfo, void *context, bool check_dex_pc) - NO_THREAD_SAFETY_ANALYSIS; + bool IsInGeneratedCode(void *context, bool check_dex_pc) NO_THREAD_SAFETY_ANALYSIS; private: std::vector<FaultHandler*> generated_code_handlers_; diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc index 333ba03..e1e133f 100644 --- a/runtime/parsed_options.cc +++ b/runtime/parsed_options.cc @@ -286,8 +286,8 @@ bool ParsedOptions::Parse(const Runtime::Options& options, bool ignore_unrecogni } } #else - // Host. Only suspend check is explicit by default. - explicit_checks_ = kExplicitSuspendCheck; + explicit_checks_ = kExplicitNullCheck | kExplicitSuspendCheck | + kExplicitStackOverflowCheck; #endif for (size_t i = 0; i < options.size(); ++i) { @@ -305,7 +305,6 @@ bool ParsedOptions::Parse(const Runtime::Options& options, bool ignore_unrecogni Exit(0); } else if (StartsWith(option, "-Xbootclasspath:")) { boot_class_path_string_ = option.substr(strlen("-Xbootclasspath:")).data(); - LOG(INFO) << "setting boot class path to " << boot_class_path_string_; } else if (option == "-classpath" || option == "-cp") { // TODO: support -Djava.class.path i++; diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 6459a52..efa205e 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -580,41 +580,10 @@ bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) { GetInstrumentation()->ForceInterpretOnly(); } - heap_ = new gc::Heap(options->heap_initial_size_, - options->heap_growth_limit_, - options->heap_min_free_, - options->heap_max_free_, - options->heap_target_utilization_, - options->foreground_heap_growth_multiplier_, - options->heap_maximum_size_, - options->image_, - options->image_isa_, - options->collector_type_, - options->background_collector_type_, - options->parallel_gc_threads_, - options->conc_gc_threads_, - options->low_memory_mode_, - options->long_pause_log_threshold_, - options->long_gc_log_threshold_, - options->ignore_max_footprint_, - options->use_tlab_, - options->verify_pre_gc_heap_, - options->verify_pre_sweeping_heap_, - options->verify_post_gc_heap_, - options->verify_pre_gc_rosalloc_, - options->verify_pre_sweeping_rosalloc_, - options->verify_post_gc_rosalloc_); - - dump_gc_performance_on_shutdown_ = options->dump_gc_performance_on_shutdown_; - - BlockSignals(); - InitPlatformSignalHandlers(); - bool implicit_checks_supported = false; switch (kRuntimeISA) { case kArm: case kThumb2: - case kX86: implicit_checks_supported = true; break; default: @@ -646,6 +615,36 @@ bool Runtime::Init(const Options& raw_options, bool ignore_unrecognized) { } } + heap_ = new gc::Heap(options->heap_initial_size_, + options->heap_growth_limit_, + options->heap_min_free_, + options->heap_max_free_, + options->heap_target_utilization_, + options->foreground_heap_growth_multiplier_, + options->heap_maximum_size_, + options->image_, + options->image_isa_, + options->collector_type_, + options->background_collector_type_, + options->parallel_gc_threads_, + options->conc_gc_threads_, + options->low_memory_mode_, + options->long_pause_log_threshold_, + options->long_gc_log_threshold_, + options->ignore_max_footprint_, + options->use_tlab_, + options->verify_pre_gc_heap_, + options->verify_pre_sweeping_heap_, + options->verify_post_gc_heap_, + options->verify_pre_gc_rosalloc_, + options->verify_pre_sweeping_rosalloc_, + options->verify_post_gc_rosalloc_); + + dump_gc_performance_on_shutdown_ = options->dump_gc_performance_on_shutdown_; + + BlockSignals(); + InitPlatformSignalHandlers(); + java_vm_ = new JavaVMExt(this, options.get()); Thread::Startup(); diff --git a/runtime/thread.cc b/runtime/thread.cc index 4147dc2..d60fb49 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -233,99 +233,47 @@ static size_t FixStackSize(size_t stack_size) { return stack_size; } -// Global variable to prevent the compiler optimizing away the page reads for the stack. -byte dont_optimize_this; - // Install a protected region in the stack. This is used to trigger a SIGSEGV if a stack // overflow is detected. It is located right below the stack_end_. Just below that // is the StackOverflow reserved region used when creating the StackOverflow // exception. -// -// There is a little complexity here that deserves a special mention. When running on the -// host (glibc), the process's main thread's stack is allocated with a special flag -// to prevent memory being allocated when it's not needed. This flag makes the -// kernel only allocate memory for the stack by growing down in memory. Because we -// want to put an mprotected region far away from that at the stack top, we need -// to make sure the pages for the stack are mapped in before we call mprotect. We do -// this by reading every page from the stack bottom (highest address) to the stack top. -// We then madvise this away. void Thread::InstallImplicitProtection(bool is_main_stack) { byte* pregion = tlsPtr_.stack_end; - byte* stack_lowmem = tlsPtr_.stack_begin; - byte* stack_top = reinterpret_cast<byte*>(reinterpret_cast<uintptr_t>(&pregion) & - ~(kPageSize - 1)); // Page containing current top of stack. -#ifndef HAVE_ANDROID_OS - bool running_on_host = true; -#else - bool running_on_host = false; -#endif - - if (running_on_host) { - // On Host, we need to map in the main stack. This must be done by reading from the - // current stack pointer downwards as the stack is mapped using VM_GROWSDOWN - // in the kernel. Any access more than a page below the current SP will cause - // a segv. - if (is_main_stack) { - // First we need to unprotect the protected region because this may - // be called more than once for a particular stack and we will crash - // if we try to read the protected page. - mprotect(pregion - kStackOverflowProtectedSize, kStackOverflowProtectedSize, PROT_READ); - - // Read every page from the high address to the low. - for (byte* p = stack_top; p > stack_lowmem; p -= kPageSize) { - dont_optimize_this = *p; - } - } - } - - // Check and place a marker word at the lowest usable address in the stack. This - // is used to prevent a double protection. constexpr uint32_t kMarker = 0xdadadada; uintptr_t *marker = reinterpret_cast<uintptr_t*>(pregion); if (*marker == kMarker) { - // The region has already been set up. But on the main stack on the host we have - // removed the protected region in order to read the stack memory. We need to put - // this back again. - if (is_main_stack && running_on_host) { - mprotect(pregion - kStackOverflowProtectedSize, kStackOverflowProtectedSize, PROT_NONE); - madvise(stack_lowmem, stack_top - stack_lowmem, MADV_DONTNEED); - } + // The region has already been set up. return; } // Add marker so that we can detect a second attempt to do this. *marker = kMarker; - if (!running_on_host) { - // Running on Android, stacks are mapped cleanly. The protected region for the - // main stack just needs to be mapped in. We do this by writing one byte per page. - for (byte* p = pregion - kStackOverflowProtectedSize; p < pregion; p += kPageSize) { - *p = 0; + pregion -= kStackOverflowProtectedSize; + + // Touch the pages in the region to map them in. Otherwise mprotect fails. Only + // need to do this on the main stack. We only need to touch one byte per page. + if (is_main_stack) { + byte* start = pregion; + byte* end = pregion + kStackOverflowProtectedSize; + while (start < end) { + *start = static_cast<byte>(0); + start += kPageSize; } } - pregion -= kStackOverflowProtectedSize; - VLOG(threads) << "installing stack protected region at " << std::hex << static_cast<void*>(pregion) << " to " << static_cast<void*>(pregion + kStackOverflowProtectedSize - 1); - if (mprotect(pregion, kStackOverflowProtectedSize, PROT_NONE) == -1) { LOG(FATAL) << "Unable to create protected region in stack for implicit overflow check. Reason:" << strerror(errno); } // Tell the kernel that we won't be needing these pages any more. - // NB. madvise will probably write zeroes into the memory (on linux it does). if (is_main_stack) { - if (running_on_host) { - // On the host, it's the whole stack (minus a page to prevent overwrite of stack top). - madvise(stack_lowmem, stack_top - stack_lowmem - kPageSize, MADV_DONTNEED); - } else { - // On Android, just the protected region. - madvise(pregion, kStackOverflowProtectedSize, MADV_DONTNEED); - } + madvise(pregion, kStackOverflowProtectedSize, MADV_DONTNEED); } } @@ -586,17 +534,13 @@ void Thread::InitStackHwm() { // Install the protected region if we are doing implicit overflow checks. if (implicit_stack_check) { if (is_main_thread) { - size_t guardsize; - pthread_attr_t attributes; - CHECK_PTHREAD_CALL(pthread_attr_init, (&attributes), "guard size query"); - CHECK_PTHREAD_CALL(pthread_attr_getguardsize, (&attributes, &guardsize), "guard size query"); - CHECK_PTHREAD_CALL(pthread_attr_destroy, (&attributes), "guard size query"); - // The main thread might have protected region at the bottom. We need + // The main thread has a 16K protected region at the bottom. We need // to install our own region so we need to move the limits // of the stack to make room for it. - tlsPtr_.stack_begin += guardsize; - tlsPtr_.stack_end += guardsize; - tlsPtr_.stack_size -= guardsize; + constexpr uint32_t kDelta = 16 * KB; + tlsPtr_.stack_begin += kDelta; + tlsPtr_.stack_end += kDelta; + tlsPtr_.stack_size -= kDelta; } InstallImplicitProtection(is_main_thread); } diff --git a/runtime/thread_linux.cc b/runtime/thread_linux.cc index 518211b..ee66ccc 100644 --- a/runtime/thread_linux.cc +++ b/runtime/thread_linux.cc @@ -35,8 +35,8 @@ static void SigAltStack(stack_t* new_stack, stack_t* old_stack) { void Thread::SetUpAlternateSignalStack() { // Create and set an alternate signal stack. stack_t ss; - ss.ss_sp = new uint8_t[SIGSTKSZ * 2]; // NB. this is 16K. - ss.ss_size = SIGSTKSZ * 2; + ss.ss_sp = new uint8_t[SIGSTKSZ]; + ss.ss_size = SIGSTKSZ; ss.ss_flags = 0; CHECK(ss.ss_sp != NULL); SigAltStack(&ss, NULL); @@ -56,7 +56,7 @@ void Thread::TearDownAlternateSignalStack() { // Tell the kernel to stop using it. ss.ss_sp = NULL; ss.ss_flags = SS_DISABLE; - ss.ss_size = SIGSTKSZ * 2; // Avoid ENOMEM failure with Mac OS' buggy libc. + ss.ss_size = SIGSTKSZ; // Avoid ENOMEM failure with Mac OS' buggy libc. SigAltStack(&ss, NULL); // Free it. |