DLLEXPORT int julia_trampoline(int argc, char **argv, int (*pmain)(int ac,char *av[])) { #if defined(_WIN32) //&& !defined(_WIN64) SetUnhandledExceptionFilter(exception_handler); #endif unsigned char * p = (unsigned char *) &__stack_chk_guard; char a = p[sizeof(__stack_chk_guard)-1]; char b = p[sizeof(__stack_chk_guard)-2]; char c = p[0]; /* If you have the ability to generate random numbers in your kernel then use them */ p[sizeof(__stack_chk_guard)-1] = 255; p[sizeof(__stack_chk_guard)-2] = '\n'; p[0] = 0; #ifdef COPY_STACKS // initialize base context of root task jl_root_task->stackbase = (char*)&argc; if (jl_setjmp(jl_root_task->base_ctx, 0)) { jl_switch_stack(jl_current_task, jl_jmp_target); } #endif int ret = pmain(argc, argv); p[sizeof(__stack_chk_guard)-1] = a; p[sizeof(__stack_chk_guard)-2] = b; p[0] = c; return ret; }
static jl_value_t *eval_body(jl_array_t *stmts, jl_value_t **locals, size_t nl, int start) { jl_savestate_t __ss; jl_jmp_buf __handlr; size_t i=start; while (1) { jl_value_t *stmt = jl_cellref(stmts,i); if (jl_is_gotonode(stmt)) { i = label_idx(jl_fieldref(stmt,0), stmts); continue; } if (jl_is_expr(stmt)) { jl_sym_t *head = ((jl_expr_t*)stmt)->head; if (head == goto_ifnot_sym) { jl_value_t *cond = eval(jl_exprarg(stmt,0), locals, nl); if (cond == jl_false) { i = label_idx(jl_exprarg(stmt,1), stmts); continue; } else if (cond != jl_true) { jl_type_error_rt("toplevel", "if", (jl_value_t*)jl_bool_type, cond); } } else if (head == return_sym) { return eval(jl_exprarg(stmt,0), locals, nl); } else if (head == enter_sym) { jl_enter_handler(&__ss, &__handlr); if (!jl_setjmp(__handlr,1)) { return eval_body(stmts, locals, nl, i+1); } else { i = label_idx(jl_exprarg(stmt,0), stmts); continue; } } else if (head == leave_sym) { int hand_n_leave = jl_unbox_long(jl_exprarg(stmt,0)); jl_pop_handler(hand_n_leave); } else { eval(stmt, locals, nl); } } else { eval(stmt, locals, nl); } i++; } assert(0); return NULL; }
DLLEXPORT int julia_trampoline(int argc, char *argv[], int (*pmain)(int ac,char *av[])) { #ifdef COPY_STACKS // initialize base context of root task jl_root_task->stackbase = (char*)&argc; if (jl_setjmp(jl_root_task->base_ctx, 1)) { jl_switch_stack(jl_current_task, jl_jmp_target); } #endif return pmain(argc, argv); }
JL_DLLEXPORT void jl_(void *jl_value) { jl_ptls_t ptls = jl_get_ptls_states(); jl_jmp_buf *old_buf = ptls->safe_restore; jl_jmp_buf buf; ptls->safe_restore = &buf; if (!jl_setjmp(buf, 0)) { jl_static_show((JL_STREAM*)STDERR_FILENO, (jl_value_t*)jl_value); jl_printf((JL_STREAM*)STDERR_FILENO,"\n"); } else { jl_printf((JL_STREAM*)STDERR_FILENO, "\n!!! ERROR in jl_ -- ABORTING !!!\n"); } ptls->safe_restore = old_buf; }
static size_t jl_safe_read_mem(const volatile char *ptr, char *out, size_t len) { jl_ptls_t ptls = jl_get_ptls_states(); jl_jmp_buf *old_buf = ptls->safe_restore; jl_jmp_buf buf; ptls->safe_restore = &buf; volatile size_t i = 0; if (!jl_setjmp(buf, 0)) { for (;i < len;i++) { out[i] = ptr[i]; } } ptls->safe_restore = old_buf; return i; }
size_t jl_unw_stepn(bt_cursor_t *cursor, uintptr_t *ip, uintptr_t *sp, size_t maxsize) { jl_ptls_t ptls = jl_get_ptls_states(); volatile size_t n = 0; uintptr_t nullsp; #if defined(_OS_WINDOWS_) && !defined(_CPU_X86_64_) assert(!jl_in_stackwalk); jl_in_stackwalk = 1; #endif #if !defined(_OS_WINDOWS_) jl_jmp_buf *old_buf = ptls->safe_restore; jl_jmp_buf buf; if (!jl_setjmp(buf, 0)) { ptls->safe_restore = &buf; #endif while (1) { if (n >= maxsize) { n = maxsize; // return maxsize + 1 if ran out of space break; } if (!jl_unw_step(cursor, &ip[n], sp ? &sp[n] : &nullsp)) break; n++; } n++; #if !defined(_OS_WINDOWS_) } else { // The unwinding fails likely because a invalid memory read. // Back off one frame since it is likely invalid. // This seems to be good enough on x86 to make the LLVM debug info // reader happy. if (n > 0) n -= 1; } ptls->safe_restore = old_buf; #endif #if defined(_OS_WINDOWS_) && !defined(_CPU_X86_64_) jl_in_stackwalk = 0; #endif return n; }
DLLEXPORT void *jl_eval_string(char *str) { #ifdef COPY_STACKS jl_root_task->stackbase = (char*)&str; if (jl_setjmp(jl_root_task->base_ctx, 1)) { jl_switch_stack(jl_current_task, jl_jmp_target); } #endif jl_value_t *r; JL_TRY { jl_value_t *ast = jl_parse_input_line(str); JL_GC_PUSH1(&ast); r = jl_toplevel_eval(ast); JL_GC_POP(); } JL_CATCH { //jl_show(jl_stderr_obj(), jl_exception_in_transit); r = NULL; } return r; }
static void *signal_listener(void *arg) { static uintptr_t bt_data[JL_MAX_BT_SIZE + 1]; static size_t bt_size = 0; sigset_t sset; int sig, critical, profile; jl_sigsetset(&sset); #ifdef HAVE_KEVENT struct kevent ev; int sigqueue = kqueue(); if (sigqueue == -1) { perror("signal kqueue"); } else { kqueue_signal(&sigqueue, &ev, SIGINT); kqueue_signal(&sigqueue, &ev, SIGTERM); kqueue_signal(&sigqueue, &ev, SIGABRT); kqueue_signal(&sigqueue, &ev, SIGQUIT); #ifdef SIGINFO kqueue_signal(&sigqueue, &ev, SIGINFO); #else kqueue_signal(&sigqueue, &ev, SIGUSR1); #endif #ifdef HAVE_ITIMER kqueue_signal(&sigqueue, &ev, SIGPROF); #endif } #endif while (1) { profile = 0; sig = 0; errno = 0; #ifdef HAVE_KEVENT if (sigqueue != -1) { int nevents = kevent(sigqueue, NULL, 0, &ev, 1, NULL); if (nevents == -1) { if (errno == EINTR) continue; perror("signal kevent"); } if (nevents != 1) { close(sigqueue); sigqueue = -1; continue; } sig = ev.ident; } else #endif if (sigwait(&sset, &sig)) { sig = SIGABRT; // this branch can't occur, unless we had stack memory corruption of sset } else if (!sig || errno == EINTR) { // This should never happen, but it has been observed to occur // when this thread gets used to handle run a signal handler (without SA_RESTART). // It would be nice to prohibit the kernel from doing that, by blocking signals on this thread, // (so that we aren't temporarily unable to handle the signals that this thread exists to handle) // but that sometimes results in the signals never getting delivered at all. // Apparently the only consistent way to handle signals with sigwait is all-or-nothing :( // And while sigwait handles per-process signals more sanely, // it can't really handle thread-targeted signals at all. // So signals really do seem to always just be lose-lose. continue; } #ifndef HAVE_MACH # ifdef HAVE_ITIMER profile = (sig == SIGPROF); # else profile = (sig == SIGUSR1); # endif #endif if (sig == SIGINT) { if (jl_ignore_sigint()) { continue; } else if (exit_on_sigint) { critical = 1; } else { jl_try_deliver_sigint(); continue; } } else { critical = 0; } critical |= (sig == SIGTERM); critical |= (sig == SIGABRT); critical |= (sig == SIGQUIT); #ifdef SIGINFO critical |= (sig == SIGINFO); #else critical |= (sig == SIGUSR1 && !profile); #endif int doexit = critical; #ifdef SIGINFO if (sig == SIGINFO) doexit = 0; #else if (sig == SIGUSR1) doexit = 0; #endif bt_size = 0; #if !defined(JL_DISABLE_LIBUNWIND) unw_context_t *signal_context; // sample each thread, round-robin style in reverse order // (so that thread zero gets notified last) for (int i = jl_n_threads; i-- > 0; ) { // notify thread to stop jl_thread_suspend_and_get_state(i, &signal_context); // do backtrace on thread contexts for critical signals // this part must be signal-handler safe if (critical) { bt_size += rec_backtrace_ctx(bt_data + bt_size, JL_MAX_BT_SIZE / jl_n_threads - 1, signal_context); bt_data[bt_size++] = 0; } // do backtrace for profiler if (profile && running) { if (bt_size_cur < bt_size_max - 1) { // unwinding can fail, so keep track of the current state // and restore from the SEGV handler if anything happens. jl_ptls_t ptls = jl_get_ptls_states(); jl_jmp_buf *old_buf = ptls->safe_restore; jl_jmp_buf buf; ptls->safe_restore = &buf; if (jl_setjmp(buf, 0)) { jl_safe_printf("WARNING: profiler attempt to access an invalid memory location\n"); } else { // Get backtrace data bt_size_cur += rec_backtrace_ctx((uintptr_t*)bt_data_prof + bt_size_cur, bt_size_max - bt_size_cur - 1, signal_context); } ptls->safe_restore = old_buf; // Mark the end of this block with 0 bt_data_prof[bt_size_cur++] = 0; } if (bt_size_cur >= bt_size_max - 1) { // Buffer full: Delete the timer jl_profile_stop_timer(); } } // notify thread to resume jl_thread_resume(i, sig); } #endif // this part is async with the running of the rest of the program // and must be thread-safe, but not necessarily signal-handler safe if (critical) { jl_critical_error(sig, NULL, bt_data, &bt_size); if (doexit) { thread0_exit_count++; jl_exit_thread0(128 + sig); } } } return NULL; }