static void signalHandler_npe_so(int signum, siginfo_t* info, void* context) { // rvmGetEnv() uses pthread_getspecific() which isn't listed as // async-signal-safe. Others (e.g. mono) do this too so we assume it is safe // in practice. Env* env = rvmGetEnv(); if (env && rvmIsNonNativeFrame(env)) { // We now know the fault occurred in non-native code and not in our // native code or in any non-async-signal-safe system function. It // should be safe to do things here that would normally be unsafe to do // in a signal handler. void* faultAddr = info->si_addr; void* stackAddr = env->currentThread->stackAddr; Class* exClass = NULL; if (faultAddr < stackAddr && faultAddr >= (void*) (stackAddr - THREAD_STACK_GUARD_SIZE)) { // StackOverflowError exClass = java_lang_StackOverflowError; } else { // At least on Linux x86 it seems like si_addr isn't always 0x0 even // if a read of address 0x0 triggered SIGSEGV so we assume // everything that isn't a stack overflow is a read of address 0x0 // and throw NullPointerException. exClass = java_lang_NullPointerException; } if (exClass) { Object* throwable = rvmAllocateObject(env, exClass); if (!throwable) { throwable = rvmExceptionClear(env); } Frame fakeFrame; fakeFrame.prev = (Frame*) getFramePointer((ucontext_t*) context); fakeFrame.returnAddress = getPC((ucontext_t*) context); CallStack* callStack = captureCallStackFromFrame(env, &fakeFrame); rvmSetLongInstanceFieldValue(env, throwable, stackStateField, PTR_TO_LONG(callStack)); rvmRaiseException(env, throwable); } } struct sigaction sa; sa.sa_flags = 0; sa.sa_handler = SIG_DFL; sigaction(signum, &sa, NULL); kill(0, signum); }
static void signalHandler_npe_so(int signum, siginfo_t* info, void* context) { // SIGSEGV/SIGBUS are synchronous signals so we shouldn't have to worry about only calling // async-signal-safe functions here. Env* env = rvmGetEnv(); if (env && rvmIsNonNativeFrame(env)) { // We now know the fault occurred in non-native code. void* faultAddr = info->si_addr; void* stackAddr = env->currentThread->stackAddr; Class* exClass = NULL; if (faultAddr < stackAddr && faultAddr >= (void*) (stackAddr - THREAD_STACK_GUARD_SIZE)) { // StackOverflowError exClass = java_lang_StackOverflowError; } else { // At least on Linux x86 it seems like si_addr isn't always 0x0 even // if a read of address 0x0 triggered SIGSEGV so we assume // everything that isn't a stack overflow is a read of address 0x0 // and throw NullPointerException. exClass = java_lang_NullPointerException; } if (exClass) { Frame fakeFrame; fakeFrame.prev = (Frame*) getFramePointer((ucontext_t*) context); fakeFrame.returnAddress = getPC((ucontext_t*) context); Object* throwable = NULL; CallStack* callStack = captureCallStackFromFrame(env, &fakeFrame); if (callStack) { throwable = rvmAllocateObject(env, exClass); if (throwable) { rvmCallVoidClassMethod(env, exClass, throwableInitMethod, throwable, PTR_TO_LONG(callStack)); if (rvmExceptionCheck(env)) { throwable = NULL; } } } if (!throwable) { throwable = rvmExceptionClear(env); } rvmRaiseException(env, throwable); // Never returns! } } }
void _bcThrowIfExceptionOccurred(Env* env) { Object* throwable = rvmExceptionOccurred(env); if (throwable) rvmRaiseException(env, throwable); }
void _bcThrow(Env* env, Object* throwable) { rvmRaiseException(env, throwable); }
void _rvmProxyHandler(CallInfo* callInfo) { Env* env = (Env*) proxy0NextPtr(callInfo); Object* receiver = (Object*) proxy0NextPtr(callInfo); Class* proxyClass = receiver->clazz; ProxyClassData* proxyClassData = (ProxyClassData*) proxyClass->data; LookupKey key; memset(&key, 0, sizeof(LookupKey)); key.name = (char*) env->reserved0; key.desc = (char*) env->reserved1; LookupEntry* entry; HASH_FIND(hh, proxyClassData->lookupsHash, &key, sizeof(LookupKey), entry); if (!entry) { rvmThrowNoSuchMethodError(env, "Failed to determine which method was called on proxy class"); goto error; } ProxyMethod* method = entry->method; rvmPushGatewayFrameProxy(env, method); jint argsCount = rvmGetParameterCount((Method*) method); jvalue *jvalueArgs = NULL; if (argsCount > 0) { jvalueArgs = (jvalue*) rvmAllocateMemory(env, sizeof(jvalue) * argsCount); if (!jvalueArgs) goto errorPop; const char* desc = method->method.desc; const char* c; jint i = 0; while ((c = rvmGetNextParameterType(&desc))) { switch (c[0]) { case 'B': jvalueArgs[i++].b = (jbyte) proxy0NextInt(callInfo); break; case 'Z': jvalueArgs[i++].z = (jboolean) proxy0NextInt(callInfo); break; case 'S': jvalueArgs[i++].s = (jshort) proxy0NextInt(callInfo); break; case 'C': jvalueArgs[i++].c = (jchar) proxy0NextInt(callInfo); break; case 'I': jvalueArgs[i++].i = proxy0NextInt(callInfo); break; case 'J': jvalueArgs[i++].j = proxy0NextLong(callInfo); break; case 'F': jvalueArgs[i++].f = proxy0NextFloat(callInfo); break; case 'D': jvalueArgs[i++].d = proxy0NextDouble(callInfo); break; case '[': case 'L': jvalueArgs[i++].l = (jobject) proxy0NextPtr(callInfo); break; } } } jvalue returnValue; proxyClassData->handler(env, receiver, method, jvalueArgs, &returnValue); rvmPopGatewayFrame(env); if (rvmExceptionCheck(env)) goto error; proxy0ReturnInt(callInfo, 0); switch (rvmGetReturnType(method->method.desc)[0]) { case 'B': proxy0ReturnInt(callInfo, (jint) returnValue.b); break; case 'Z': proxy0ReturnInt(callInfo, (jint) returnValue.z); break; case 'S': proxy0ReturnInt(callInfo, (jint) returnValue.s); break; case 'C': proxy0ReturnInt(callInfo, (jint) returnValue.c); break; case 'I': proxy0ReturnInt(callInfo, returnValue.i); break; case 'J': proxy0ReturnLong(callInfo, returnValue.j); break; case 'F': proxy0ReturnFloat(callInfo, returnValue.f); break; case 'D': proxy0ReturnDouble(callInfo, returnValue.d); break; case '[': case 'L': proxy0ReturnPtr(callInfo, returnValue.l); break; } return; errorPop: rvmPopGatewayFrame(env); error: rvmRaiseException(env, rvmExceptionOccurred(env)); }