diff options
author | 卜部昌平 <shyouhei@ruby-lang.org> | 2019-10-10 11:55:43 +0900 |
---|---|---|
committer | 卜部昌平 <shyouhei@ruby-lang.org> | 2019-10-10 12:07:38 +0900 |
commit | 9c3153e0da991e1a7df9b4cf91d6830effc79b22 (patch) | |
tree | 67096a78da04f6592d79f3d81b2c4f7b6b0353a2 /error.c | |
parent | 25100c469758dd3676ec608ed27fd89248980666 (diff) | |
download | ruby-9c3153e0da991e1a7df9b4cf91d6830effc79b22.tar.gz |
allow rb_raise from outside of GVL
Now that allocation routines like ALLOC_N() can raise exceptions
on integer overflows. This is a problem when the calling thread
has no GVL. Memory allocations has been allowed without it, but
can still fail.
Let's just relax rb_raise's restriction so that we can call it
with or without GVL. With GVL the behaviour is unchanged. With
no GVL, wait for it.
Also, integer overflows can theoretically occur during GC when
we expand the object space. We cannot do so much then. Call
rb_memerror and let that routine abort the process.
Diffstat (limited to 'error.c')
-rw-r--r-- | error.c | 39 |
1 files changed, 35 insertions, 4 deletions
@@ -11,6 +11,7 @@ #include "ruby/encoding.h" #include "ruby/st.h" +#include "ruby/thread.h" #include "internal.h" #include "ruby_assert.h" #include "vm_core.h" @@ -2604,16 +2605,46 @@ rb_enc_raise(rb_encoding *enc, VALUE exc, const char *fmt, ...) rb_exc_raise(rb_exc_new3(exc, mesg)); } +struct rb_raise_tag { + VALUE exc; + const char *fmt; + va_list *args; +}; + +static void * +rb_vraise(void *ptr) +{ + struct rb_raise_tag *argv = ptr; + VALUE msg = rb_vsprintf(argv->fmt, *argv->args); + VALUE exc = rb_exc_new3(argv->exc, msg); + rb_exc_raise(exc); + UNREACHABLE_RETURN(NULL); +} + void rb_raise(VALUE exc, const char *fmt, ...) { va_list args; - VALUE mesg; - va_start(args, fmt); - mesg = rb_vsprintf(fmt, args); + struct rb_raise_tag argv = { + exc, fmt, &args, + }; + + if (ruby_thread_has_gvl_p()) { + rb_vraise(&argv); + UNREACHABLE; + } + else if (ruby_native_thread_p()) { + rb_thread_call_with_gvl(rb_vraise, &argv); + UNREACHABLE; + } + else { + /* Not in a ruby thread */ + vfprintf(stderr, fmt, args); + abort(); + } + va_end(args); - rb_exc_raise(rb_exc_new3(exc, mesg)); } NORETURN(static void raise_loaderror(VALUE path, VALUE mesg)); |