diff --git a/compile.c b/compile.c index 78870ee0510043..f2977c092b4d74 100644 --- a/compile.c +++ b/compile.c @@ -2522,6 +2522,8 @@ iseq_set_exception_table(rb_iseq_t *iseq) if (tlen > 0) { struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen)); table->size = tlen; + struct iseq_catch_table_entry *rescue_entry = NULL; + bool multiple_rescue = false; for (i = 0; i < table->size; i++) { ptr = RARRAY_CONST_PTR_TRANSIENT(tptr[i]); @@ -2532,6 +2534,30 @@ iseq_set_exception_table(rb_iseq_t *iseq) entry->iseq = (rb_iseq_t *)ptr[3]; RB_OBJ_WRITTEN(iseq, Qundef, entry->iseq); + /* TODO: Dirty Hack! Fix me */ + /* This checks when a rescue catch entry and ensure catch + * entry have the same start, the rescue catch end is not + * after the end of the ensure end. This fixes an issue + * where a control flow keyword such as next inside a + * begin block results in the rescue catch entry covering + * the ensure block. + */ + if (entry->type == CATCH_TYPE_RESCUE) { + if (rescue_entry) { + multiple_rescue = true; + } + else { + rescue_entry = entry; + } + } + else if (entry->type == CATCH_TYPE_ENSURE && + rescue_entry && + !multiple_rescue && + entry->start == rescue_entry->start && + rescue_entry->end > entry->end) { + rescue_entry->end = entry->end; + } + /* stack depth */ if (ptr[4]) { LABEL *lobj = (LABEL *)(ptr[4] & ~1); diff --git a/test/ruby/test_exception.rb b/test/ruby/test_exception.rb index 087bcda5acbfca..e6454b9adfe852 100644 --- a/test/ruby/test_exception.rb +++ b/test/ruby/test_exception.rb @@ -78,6 +78,35 @@ def test_exception_ensure_2 # just duplication? assert(!bad) end + def test_exception_in_ensure_with_next + string = "[ruby-core:82936] [Bug #13930]" + assert_raise_with_message(RuntimeError, string) do + lambda do + next + rescue + assert(false) + ensure + raise string + end.call + assert(false) + end + end + + def test_exception_in_ensure_with_return + @string = "[ruby-core:97104] [Bug #16618]" + def self.meow + return + assert(false) + rescue + assert(false) + ensure + raise @string + end + assert_raise_with_message(RuntimeError, @string) do + meow + end + end + def test_errinfo_in_debug bug9568 = EnvUtil.labeled_class("[ruby-core:61091] [Bug #9568]", RuntimeError) do def to_s