// Be very cautious and default to not handling; we don't want to accidentally // silence real crashes from real bugs. static bool HandleSignal(int signum, siginfo_t *info, void *ctx) { CONTEXT *context = (CONTEXT *)ctx; uint8_t **ppc = ContextToPC(context); uint8_t *pc = *ppc; void *faultingAddress = info->si_addr; JSRuntime *rt = RuntimeForCurrentThread(); // Don't allow recursive handling of signals, see AutoSetHandlingSignal. if (!rt || rt->handlingSignal) return false; AutoSetHandlingSignal handling(rt); if (rt->jitRuntime() && rt->jitRuntime()->handleAccessViolation(rt, faultingAddress)) return true; AsmJSActivation *activation = InnermostAsmJSActivation(); if (!activation) return false; const AsmJSModule &module = activation->module(); if (HandleSimulatorInterrupt(rt, activation, faultingAddress)) { JSRuntime::AutoLockForInterrupt lock(rt); module.unprotectCode(rt); return true; } if (!module.containsPC(pc)) return false; // If we faulted trying to execute code in 'module', this must be an // interrupt callback (see RequestInterruptForAsmJSCode). Redirect // execution to a trampoline which will call js::HandleExecutionInterrupt. // The trampoline will jump to activation->resumePC if execution isn't // interrupted. if (module.containsPC(faultingAddress)) { activation->setInterrupted(pc); *ppc = module.interruptExit(); JSRuntime::AutoLockForInterrupt lock(rt); module.unprotectCode(rt); return true; } # if defined(JS_CODEGEN_X64) // These checks aren't necessary, but, since we can, check anyway to make // sure we aren't covering up a real bug. if (!module.maybeHeap() || faultingAddress < module.maybeHeap() || faultingAddress >= module.maybeHeap() + AsmJSBufferProtectedSize) { return false; } const AsmJSHeapAccess *heapAccess = module.lookupHeapAccess(pc); if (!heapAccess) return false; // We now know that this is an out-of-bounds access made by an asm.js // load/store that we should handle. If this is a load, assign the // JS-defined result value to the destination register (ToInt32(undefined) // or ToNumber(undefined), determined by the type of the destination // register) and set the PC to the next op. Upon return from the handler, // execution will resume at this next PC. if (heapAccess->isLoad()) SetRegisterToCoercedUndefined(context, heapAccess->isFloat32Load(), heapAccess->loadedReg()); *ppc += heapAccess->opLength(); return true; # else return false; # endif }
static bool HandleMachException(JSRuntime *rt, const ExceptionRequest &request) { // Don't allow recursive handling of signals, see AutoSetHandlingSignal. if (rt->handlingSignal) return false; AutoSetHandlingSignal handling(rt); // Get the port of the JSRuntime's thread from the message. mach_port_t rtThread = request.body.thread.name; // Read out the JSRuntime thread's register state. x86_thread_state_t state; unsigned int count = x86_THREAD_STATE_COUNT; kern_return_t kret; kret = thread_get_state(rtThread, x86_THREAD_STATE, (thread_state_t)&state, &count); if (kret != KERN_SUCCESS) return false; uint8_t **ppc = ContextToPC(state); uint8_t *pc = *ppc; if (request.body.exception != EXC_BAD_ACCESS || request.body.codeCnt != 2) return false; void *faultingAddress = (void*)request.body.code[1]; if (rt->jitRuntime() && rt->jitRuntime()->handleAccessViolation(rt, faultingAddress)) return true; AsmJSActivation *activation = rt->mainThread.asmJSActivationStackFromAnyThread(); if (!activation) return false; const AsmJSModule &module = activation->module(); if (HandleSimulatorInterrupt(rt, activation, faultingAddress)) { JSRuntime::AutoLockForInterrupt lock(rt); module.unprotectCode(rt); return true; } if (!module.containsPC(pc)) return false; // If we faulted trying to execute code in 'module', this must be an // interrupt callback (see RequestInterruptForAsmJSCode). Redirect // execution to a trampoline which will call js::HandleExecutionInterrupt. // The trampoline will jump to activation->resumePC if execution isn't // interrupted. if (module.containsPC(faultingAddress)) { activation->setInterrupted(pc); *ppc = module.interruptExit(); JSRuntime::AutoLockForInterrupt lock(rt); module.unprotectCode(rt); // Update the thread state with the new pc. kret = thread_set_state(rtThread, x86_THREAD_STATE, (thread_state_t)&state, x86_THREAD_STATE_COUNT); return kret == KERN_SUCCESS; } # if defined(JS_CODEGEN_X64) // These checks aren't necessary, but, since we can, check anyway to make // sure we aren't covering up a real bug. if (!module.maybeHeap() || faultingAddress < module.maybeHeap() || faultingAddress >= module.maybeHeap() + AsmJSBufferProtectedSize) { return false; } const AsmJSHeapAccess *heapAccess = module.lookupHeapAccess(pc); if (!heapAccess) return false; // We now know that this is an out-of-bounds access made by an asm.js // load/store that we should handle. If this is a load, assign the // JS-defined result value to the destination register (ToInt32(undefined) // or ToNumber(undefined), determined by the type of the destination // register) and set the PC to the next op. Upon return from the handler, // execution will resume at this next PC. if (heapAccess->isLoad()) { if (!SetRegisterToCoercedUndefined(rtThread, state.uts.ts64, *heapAccess)) return false; } *ppc += heapAccess->opLength(); // Update the thread state with the new pc. kret = thread_set_state(rtThread, x86_THREAD_STATE, (thread_state_t)&state, x86_THREAD_STATE_COUNT); if (kret != KERN_SUCCESS) return false; return true; # else return false; # endif }