mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
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.
This commit is contained in:
parent
25100c4697
commit
9c3153e0da
3 changed files with 46 additions and 23 deletions
|
@ -1942,6 +1942,7 @@ error.$(OBJEXT): $(CCAN_DIR)/list/list.h
|
|||
error.$(OBJEXT): $(CCAN_DIR)/str/str.h
|
||||
error.$(OBJEXT): $(hdrdir)/ruby.h
|
||||
error.$(OBJEXT): $(hdrdir)/ruby/ruby.h
|
||||
error.$(OBJEXT): $(hdrdir)/ruby/thread.h
|
||||
error.$(OBJEXT): {$(VPATH)}assert.h
|
||||
error.$(OBJEXT): {$(VPATH)}config.h
|
||||
error.$(OBJEXT): {$(VPATH)}defines.h
|
||||
|
|
39
error.c
39
error.c
|
@ -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));
|
||||
|
|
29
gc.c
29
gc.c
|
@ -172,6 +172,9 @@ size_mul_or_raise(size_t x, size_t y, VALUE exc)
|
|||
if (LIKELY(!t.left)) {
|
||||
return t.right;
|
||||
}
|
||||
else if (rb_during_gc()) {
|
||||
rb_memerror(); /* or...? */
|
||||
}
|
||||
else {
|
||||
rb_raise(
|
||||
exc,
|
||||
|
@ -195,6 +198,9 @@ size_mul_add_or_raise(size_t x, size_t y, size_t z, VALUE exc)
|
|||
if (LIKELY(!t.left)) {
|
||||
return t.right;
|
||||
}
|
||||
else if (rb_during_gc()) {
|
||||
rb_memerror(); /* or...? */
|
||||
}
|
||||
else {
|
||||
rb_raise(
|
||||
exc,
|
||||
|
@ -219,6 +225,9 @@ size_mul_add_mul_or_raise(size_t x, size_t y, size_t z, size_t w, VALUE exc)
|
|||
if (LIKELY(!t.left)) {
|
||||
return t.right;
|
||||
}
|
||||
else if (rb_during_gc()) {
|
||||
rb_memerror(); /* or...? */
|
||||
}
|
||||
else {
|
||||
rb_raise(
|
||||
exc,
|
||||
|
@ -9590,28 +9599,10 @@ objspace_reachable_objects_from_root(rb_objspace_t *objspace, void (func)(const
|
|||
|
||||
static void objspace_xfree(rb_objspace_t *objspace, void *ptr, size_t size);
|
||||
|
||||
static void *
|
||||
negative_size_allocation_error_with_gvl(void *ptr)
|
||||
{
|
||||
rb_raise(rb_eNoMemError, "%s", (const char *)ptr);
|
||||
return 0; /* should not be reached */
|
||||
}
|
||||
|
||||
static void
|
||||
negative_size_allocation_error(const char *msg)
|
||||
{
|
||||
if (ruby_thread_has_gvl_p()) {
|
||||
rb_raise(rb_eNoMemError, "%s", msg);
|
||||
}
|
||||
else {
|
||||
if (ruby_native_thread_p()) {
|
||||
rb_thread_call_with_gvl(negative_size_allocation_error_with_gvl, (void *)msg);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "[FATAL] %s\n", msg);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
rb_raise(rb_eNoMemError, "%s", msg);
|
||||
}
|
||||
|
||||
static void *
|
||||
|
|
Loading…
Add table
Reference in a new issue