summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author卜部昌平 <shyouhei@ruby-lang.org>2019-10-10 11:55:43 +0900
committer卜部昌平 <shyouhei@ruby-lang.org>2019-10-10 12:07:38 +0900
commit9c3153e0da991e1a7df9b4cf91d6830effc79b22 (patch)
tree67096a78da04f6592d79f3d81b2c4f7b6b0353a2
parent25100c469758dd3676ec608ed27fd89248980666 (diff)
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.
-rw-r--r--common.mk1
-rw-r--r--error.c39
-rw-r--r--gc.c29
3 files changed, 46 insertions, 23 deletions
diff --git a/common.mk b/common.mk
index ff56a0c93f..236d40ed04 100644
--- a/common.mk
+++ b/common.mk
@@ -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
diff --git a/error.c b/error.c
index e29910ae92..3a63a5f2a9 100644
--- a/error.c
+++ b/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));
diff --git a/gc.c b/gc.c
index f4292370a0..cc4ea12250 100644
--- a/gc.c
+++ b/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 *