It is not safe to execute jit code in signal handler context. One of the reasons is that throwing-by-signal mechanisms don't work in code executed from signal handler. That's becasue kernel will not execute user defined signal handler for SIGSEGV when second signal occures while executing the handler.
This issue is addressed by introducing "bottom halfs". These are functions which are executed in normal context immediately after signal handler returns. They are installed by manipulating ucontext_t structure associated with signal handler. Signed-off-by: Tomek Grabiec <tgrab...@gmail.com> --- arch/x86/signal.c | 28 ++++++++++++++++++++++++++++ include/vm/signal.h | 3 +++ vm/signal.c | 45 +++++++++++++++++++++------------------------ 3 files changed, 52 insertions(+), 24 deletions(-) diff --git a/arch/x86/signal.c b/arch/x86/signal.c index 6b59881..61d7eba 100644 --- a/arch/x86/signal.c +++ b/arch/x86/signal.c @@ -30,6 +30,8 @@ #include <arch/stack-frame.h> #include <arch/signal.h> +#include <vm/signal.h> + bool signal_from_jit_method(void *ctx) { ucontext_t *uc; @@ -51,3 +53,29 @@ struct compilation_unit *get_signal_source_cu(void *ctx) uc = ctx; return get_cu_from_native_addr(uc->uc_mcontext.gregs[REG_IP]); } + +/** + * install_signal_bh - installs signal's bottom half function by + * modifying user context so that control will be returned to @bh + * when signal handler returns. When @bh function returns, the + * control should be returned to the source of the signal. + * + * @ctx: pointer to struct ucontext_t + * @bh: bottom half function to install + */ +int install_signal_bh(void *ctx, signal_bh_fn bh) +{ + unsigned long *stack; + ucontext_t *uc; + + uc = ctx; + + /* push return address on stack */ + stack = (unsigned long*)uc->uc_mcontext.gregs[REG_SP] - 1; + *stack = uc->uc_mcontext.gregs[REG_IP]; + uc->uc_mcontext.gregs[REG_SP] -= sizeof(unsigned long); + + uc->uc_mcontext.gregs[REG_IP] = (unsigned long)bh; + + return 0; +} diff --git a/include/vm/signal.h b/include/vm/signal.h index 8aee067..dad9381 100644 --- a/include/vm/signal.h +++ b/include/vm/signal.h @@ -1,6 +1,9 @@ #ifndef VM_SIGNAL_H #define VM_SIGNAL_H +typedef void (*signal_bh_fn)(void); + void setup_signal_handlers(void); +int install_signal_bh(void *ctx, signal_bh_fn bh); #endif /* VM_SIGNAL_H */ diff --git a/vm/signal.c b/vm/signal.c index 747276a..d52ea50 100644 --- a/vm/signal.c +++ b/vm/signal.c @@ -27,6 +27,7 @@ #include <jit/exception.h> #include <vm/backtrace.h> +#include <vm/signal.h> #include <vm/class.h> #include <arch/signal.h> @@ -35,25 +36,28 @@ #include <stddef.h> #include <unistd.h> +static void throw_arithmetic_exception(void) +{ + signal_new_exception("java/lang/ArithmeticException", + "division by zero"); + throw_from_native(0); +} + +static void throw_null_pointer_exception(void) +{ + signal_new_exception("java/lang/NullPointerException", NULL); + throw_from_native(0); +} + static void sigfpe_handler(int sig, siginfo_t *si, void *ctx) { if (signal_from_jit_method(ctx) && si->si_code == FPE_INTDIV) { - struct object *exception; - - /* TODO: exception's stack trace should be filled using ctx */ - exception = new_exception( - "java/lang/ArithmeticException", "division by zero"); - if (exception == NULL) { - /* TODO: throw OutOfMemoryError */ - fprintf(stderr, "%s: Out of memory\n", __func__); - goto exit; - } + if (install_signal_bh(ctx, throw_arithmetic_exception) == 0) + return; - throw_exception_from_signal(ctx, exception); - return; + fprintf(stderr, "%s: install_signal_bh() failed.\n", __func__); } - exit: print_backtrace_and_die(sig, si, ctx); } @@ -65,23 +69,16 @@ static void sigsegv_handler(int sig, siginfo_t *si, void *ctx) /* Assume that zero-page access is caused by dereferencing a null pointer */ if ((unsigned long)si->si_addr < (unsigned long)getpagesize()) { - struct object *exception; - /* We must be extra caucious here because IP might be invalid */ if (get_signal_source_cu(ctx) == NULL) goto exit; - /* TODO: exception's stack trace should be filled using ctx */ - exception = new_exception("java/lang/NullPointerException", NULL); - if (exception == NULL) { - /* TODO: throw OutOfMemoryError */ - fprintf(stderr, "%s: Out of memory\n", __func__); - goto exit; - } + if (install_signal_bh(ctx, throw_null_pointer_exception) == 0) + return; - throw_exception_from_signal(ctx, exception); - return; + fprintf(stderr, "%s: install_signal_bh() failed.\n", __func__); + goto exit; } /* Check if exception was triggered by exception guard */ -- 1.6.0.6 ------------------------------------------------------------------------------ _______________________________________________ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel