diff options
author | Nobuyoshi Nakada <[email protected]> | 2022-11-11 10:37:34 +0900 |
---|---|---|
committer | Nobuyoshi Nakada <[email protected]> | 2022-11-22 00:33:19 +0900 |
commit | 5b959e238e5b7c18d6a1a5f5d9b4b2063de628fe (patch) | |
tree | 4a43a7133e16bac2c105915960a642dc10f969c7 /eval.c | |
parent | 1f0888ab3e699a1083cddad84b0d8cb28e15ad8e (diff) |
[Bug #19016] re-order error handling at cleanup
Build and store the error message with `#detailed_message` before
terminating all Ractors, then show the message later.
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/6778
Diffstat (limited to 'eval.c')
-rw-r--r-- | eval.c | 97 |
1 files changed, 51 insertions, 46 deletions
@@ -100,8 +100,10 @@ ruby_init(void) { int state = ruby_setup(); if (state) { - if (RTEST(ruby_debug)) - error_print(GET_EC()); + if (RTEST(ruby_debug)) { + rb_execution_context_t *ec = GET_EC(); + rb_ec_error_print(ec, ec->errinfo); + } exit(EXIT_FAILURE); } } @@ -120,9 +122,9 @@ ruby_options(int argc, char **argv) } else { rb_ec_clear_current_thread_trace_func(ec); - state = error_handle(ec, state); + int exitcode = error_handle(ec, ec->errinfo, state); ec->errinfo = Qnil; /* just been handled */ - iseq = (void *)INT2FIX(state); + iseq = (void *)INT2FIX(exitcode); } EC_POP_TAG(); return iseq; @@ -138,7 +140,7 @@ rb_ec_fiber_scheduler_finalize(rb_execution_context_t *ec) rb_fiber_scheduler_set(Qnil); } else { - state = error_handle(ec, state); + state = error_handle(ec, ec->errinfo, state); } EC_POP_TAG(); } @@ -181,16 +183,17 @@ ruby_cleanup(int ex) } static int -rb_ec_cleanup(rb_execution_context_t *ec, enum ruby_tag_type ex0) +rb_ec_cleanup(rb_execution_context_t *ec, enum ruby_tag_type ex) { int state; - volatile VALUE errs[2] = { Qundef, Qundef }; - int nerr; + volatile VALUE save_error = Qundef; + volatile int sysex = EXIT_SUCCESS; + volatile int signaled = 0; rb_thread_t *th = rb_ec_thread_ptr(ec); rb_thread_t *const volatile th0 = th; - volatile int sysex = EXIT_SUCCESS; volatile int step = 0; - volatile enum ruby_tag_type ex = ex0; + volatile VALUE message = Qnil; + VALUE buf; rb_threadptr_interrupt(th); rb_threadptr_check_signal(th); @@ -200,56 +203,57 @@ rb_ec_cleanup(rb_execution_context_t *ec, enum ruby_tag_type ex0) SAVE_ROOT_JMPBUF(th, { RUBY_VM_CHECK_INTS(ec); }); step_0: step++; - errs[1] = ec->errinfo; + save_error = ec->errinfo; if (THROW_DATA_P(ec->errinfo)) ec->errinfo = Qnil; - ruby_init_stack(&errs[STACK_UPPER(errs, 0, 1)]); + ruby_init_stack(&message); + /* exits with failure but silently when an exception raised + * here */ SAVE_ROOT_JMPBUF(th, rb_ec_teardown(ec)); step_1: step++; + VALUE err = ec->errinfo; + int mode0 = 0, mode1 = 0; + if (err != save_error && !NIL_P(err)) { + mode0 = exiting_split(err, &sysex, &signaled); + } + + /* exceptions after here will be ignored */ + + /* build error message including causes */ + err = ATOMIC_VALUE_EXCHANGE(save_error, Qnil); + + if (!NIL_P(err) && !THROW_DATA_P(err)) { + mode1 = exiting_split(err, (mode0 & EXITING_WITH_STATUS) ? NULL : &sysex, &signaled); + if (mode1 & EXITING_WITH_MESSAGE) { + buf = rb_str_new(NULL, 0); + SAVE_ROOT_JMPBUF(th, rb_ec_error_print_detailed(ec, err, buf, Qundef)); + message = buf; + } + } + + step_2: step++; /* protect from Thread#raise */ th->status = THREAD_KILLED; - errs[0] = ec->errinfo; SAVE_ROOT_JMPBUF(th, rb_ractor_terminate_all()); + + step_3: step++; + if (!NIL_P(buf = message)) { + warn_print_str(buf); + } + else if (!NIL_OR_UNDEF_P(err = save_error) || + (ex != TAG_NONE && !((mode0|mode1) & EXITING_WITH_STATUS))) { + sysex = error_handle(ec, err, ex); + } } else { th = th0; switch (step) { case 0: goto step_0; case 1: goto step_1; - } - if (ex == 0) ex = state; - } - ec->errinfo = errs[1]; - sysex = error_handle(ec, ex); - - state = 0; - for (nerr = 0; nerr < numberof(errs); ++nerr) { - VALUE err = ATOMIC_VALUE_EXCHANGE(errs[nerr], Qnil); - VALUE sig; - - if (!RTEST(err)) continue; - - /* ec->errinfo contains a NODE while break'ing */ - if (THROW_DATA_P(err)) continue; - - if (rb_obj_is_kind_of(err, rb_eSystemExit)) { - sysex = sysexit_status(err); - break; - } - else if (rb_obj_is_kind_of(err, rb_eSignal)) { - VALUE sig = rb_ivar_get(err, id_signo); - state = NUM2INT(sig); - break; - } - else if (rb_obj_is_kind_of(err, rb_eSystemCallError) && - FIXNUM_P(sig = rb_attr_get(err, id_signo))) { - state = NUM2INT(sig); - break; - } - else if (sysex == EXIT_SUCCESS) { - sysex = EXIT_FAILURE; + case 2: goto step_2; + case 3: goto step_3; } } @@ -266,7 +270,8 @@ rb_ec_cleanup(rb_execution_context_t *ec, enum ruby_tag_type ex0) ruby_vm_destruct(th->vm); // For YJIT, call this after ruby_vm_destruct() frees jit_cont for the root fiber. rb_jit_cont_finish(); - if (state) ruby_default_signal(state); + + if (signaled) ruby_default_signal(signaled); return sysex; } |