From 4f256eefd79dbf9095e41cd9dade4e74a897d3b5 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Tue, 18 Apr 2017 15:17:26 -0400 Subject: [PATCH] fix #21369, exception state overwritten by caught internal errors --- src/codegen.cpp | 22 +++++++++------------- src/gc.c | 12 ++++++++++++ src/gf.c | 2 +- src/julia_internal.h | 2 ++ src/rtutils.c | 29 +++++++++++++++++++++++++++++ test/inference.jl | 28 ++++++++++++++++++++++++++++ 6 files changed, 81 insertions(+), 14 deletions(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index 1f31875dd9e8e..1775210587f9f 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2145,24 +2145,20 @@ static jl_value_t *static_eval(jl_value_t *ex, jl_codectx_t *ctx, int sparams=tr if (!allow_alloc) return NULL; jl_value_t **v; - JL_GC_PUSHARGS(v, n); + JL_GC_PUSHARGS(v, n+1); + v[0] = f; for (i = 0; i < n; i++) { - v[i] = static_eval(jl_exprarg(e, i+1), ctx, sparams, allow_alloc); - if (v[i] == NULL) { + v[i+1] = static_eval(jl_exprarg(e, i+1), ctx, sparams, allow_alloc); + if (v[i+1] == NULL) { JL_GC_POP(); return NULL; } } - jl_value_t *result; - JL_TRY { - if (f == jl_builtin_tuple) - result = jl_f_tuple(NULL, v, n); - else - result = jl_f_apply_type(NULL, v, n); - } - JL_CATCH { - result = NULL; - } + size_t last_age = jl_get_ptls_states()->world_age; + // here we know we're calling specific builtin functions that work in world 1. + jl_get_ptls_states()->world_age = 1; + jl_value_t *result = jl_apply_with_saved_exception_state(v, n+1, 1); + jl_get_ptls_states()->world_age = last_age; JL_GC_POP(); return result; } diff --git a/src/gc.c b/src/gc.c index 96718ed05113b..01b50408f5452 100644 --- a/src/gc.c +++ b/src/gc.c @@ -190,8 +190,20 @@ static void jl_gc_run_finalizers_in_list(jl_ptls_t ptls, arraylist_t *list) jl_value_t **items = (jl_value_t**)list->items; jl_gc_push_arraylist(ptls, list); JL_UNLOCK_NOGC(&finalizers_lock); + // from jl_apply_with_saved_exception_state; to hoist state saving out of the loop + jl_value_t *exc = ptls->exception_in_transit; + jl_array_t *bt = NULL; + JL_GC_PUSH2(&exc, &bt); + if (ptls->bt_size > 0) + bt = (jl_array_t*)jl_get_backtrace(); for (size_t i = 2;i < len;i += 2) run_finalizer(ptls, items[i], items[i + 1]); + ptls->exception_in_transit = exc; + if (bt != NULL) { + ptls->bt_size = jl_array_len(bt); + memcpy(ptls->bt_data, bt->data, ptls->bt_size * sizeof(void*)); + } + JL_GC_POP(); JL_GC_POP(); } diff --git a/src/gf.c b/src/gf.c index 0d44f879c6f47..d2be995dfdd96 100644 --- a/src/gf.c +++ b/src/gf.c @@ -266,7 +266,7 @@ jl_code_info_t *jl_type_infer(jl_method_instance_t **pli, size_t world, int forc } #endif jl_get_ptls_states()->world_age = jl_typeinf_world; - jl_svec_t *linfo_src_rettype = (jl_svec_t*)jl_apply(fargs, 3); + jl_svec_t *linfo_src_rettype = (jl_svec_t*)jl_apply_with_saved_exception_state(fargs, 3, 0); jl_get_ptls_states()->world_age = last_age; assert((li->def || li->inInference == 0) && "inference failed on a toplevel expr"); if (jl_is_svec(linfo_src_rettype) && jl_svec_len(linfo_src_rettype) == 3 && diff --git a/src/julia_internal.h b/src/julia_internal.h index e40cd82eea32c..54926651b08a2 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -640,6 +640,8 @@ size_t rec_backtrace_ctx(uintptr_t *data, size_t maxsize, bt_context_t *ctx); #ifdef LIBOSXUNWIND size_t rec_backtrace_ctx_dwarf(uintptr_t *data, size_t maxsize, bt_context_t *ctx); #endif +JL_DLLEXPORT jl_value_t *jl_get_backtrace(void); +JL_DLLEXPORT jl_value_t *jl_apply_with_saved_exception_state(jl_value_t **args, uint32_t nargs, int catch_exceptions); void jl_critical_error(int sig, bt_context_t *context, uintptr_t *bt_data, size_t *bt_size); JL_DLLEXPORT void jl_raise_debugger(void); int jl_getFunctionInfo(jl_frame_t **frames, uintptr_t pointer, int skipC, int noInline); diff --git a/src/rtutils.c b/src/rtutils.c index 66cb6bb3b7f39..935250ef8baf0 100644 --- a/src/rtutils.c +++ b/src/rtutils.c @@ -236,6 +236,35 @@ JL_DLLEXPORT void jl_pop_handler(int n) jl_eh_restore_state(eh); } +JL_DLLEXPORT jl_value_t *jl_apply_with_saved_exception_state(jl_value_t **args, uint32_t nargs, int catch_exceptions) +{ + jl_ptls_t ptls = jl_get_ptls_states(); + jl_value_t *exc = ptls->exception_in_transit; + jl_array_t *bt = NULL; + JL_GC_PUSH2(&exc, &bt); + if (ptls->bt_size > 0) + bt = (jl_array_t*)jl_get_backtrace(); + jl_value_t *v; + if (catch_exceptions) { + JL_TRY { + v = jl_apply(args, nargs); + } + JL_CATCH { + v = NULL; + } + } + else { + v = jl_apply(args, nargs); + } + ptls->exception_in_transit = exc; + if (bt != NULL) { + ptls->bt_size = jl_array_len(bt); + memcpy(ptls->bt_data, bt->data, ptls->bt_size * sizeof(void*)); + } + JL_GC_POP(); + return v; +} + // misc ----------------------------------------------------------------------- // perform f(args...) on stack diff --git a/test/inference.jl b/test/inference.jl index de62b81c68c41..1e34d4d664a3b 100644 --- a/test/inference.jl +++ b/test/inference.jl @@ -748,3 +748,31 @@ end # issue #21410 f21410(::V, ::Pair{V,E}) where {V, E} = E @test code_typed(f21410, Tuple{Ref, Pair{Ref{T},Ref{T}} where T<:Number})[1].second == Type{Ref{T}} where T<:Number + +# issue #21369 +function inf_error_21369(arg) + if arg + # invalid instantiation, causing throw during inference + Complex{String} + end +end +function break_21369() + try + error("uhoh") + catch + eval(:(inf_error_21369(false))) + bt = catch_backtrace() + i = 1 + local fr + while true + fr = Base.StackTraces.lookup(bt[i])[end] + if !fr.from_c + break + end + i += 1 + end + @test fr.func === :break_21369 + rethrow() + end +end +@test_throws ErrorException break_21369() # not TypeError