Project

General

Profile

Bug #12082

Tail-calling method can't catch exception raised by tail-called method

Added by rhenium (Kazuki Yamaguchi) over 1 year ago. Updated over 1 year ago.

Status:
Closed
Priority:
Normal
Target version:
-
[ruby-core:73871]

Description

The following code doesn't work as expected, on all versions of Ruby with tail call optimization (1.9.1 to 2.3.0).

def do_raise
  raise "should be rescued"
end
options = {
  tailcall_optimization: true,
  trace_instruction: false,
}
RubyVM::InstructionSequence.compile(<<EOF, __FILE__, __FILE__, __LINE__, options).eval
  def test_rescue
    return do_raise
    1 + 2
  rescue
    :ok
  end
EOF

p test_rescue # should print :ok, but raises "should be rescued"

Looks like nop instruction is (also) used to avoid this optimization (compile.c), but when doing early return, no nop is inserted.

I attached a (dirty) fix for this. Maybe there is a cleaner way.

Associated revisions

Revision 54542
Added by nobu (Nobuyoshi Nakada) over 1 year ago

compile.c: disable tco with rescue

  • compile.c (iseq_optimize): disable tail call optimization in rescued, rescue, and ensure blocks. [Bug #12082]

Revision 54542
Added by nobu (Nobuyoshi Nakada) over 1 year ago

compile.c: disable tco with rescue

  • compile.c (iseq_optimize): disable tail call optimization in rescued, rescue, and ensure blocks. [Bug #12082]

Revision 54548
Added by nobu (Nobuyoshi Nakada) over 1 year ago

compile.c: initialize LABEL fields

  • compile.c (new_label_body): initialize bit fields, since compile_data_alloc does not clear the memory. [Bug #12082]

Revision 54548
Added by nobu (Nobuyoshi Nakada) over 1 year ago

compile.c: initialize LABEL fields

  • compile.c (new_label_body): initialize bit fields, since compile_data_alloc does not clear the memory. [Bug #12082]

Revision 54698
Added by usa (Usaku NAKAMURA) over 1 year ago

merge revision(s) 54542,54548: [Backport #12082]

* compile.c (iseq_optimize): disable tail call optimization in
  rescued, rescue, and ensure blocks.
   [Bug #12082]

* compile.c (new_label_body): initialize bit fields, since
  compile_data_alloc does not clear the memory.  [Bug #12082]

Revision 54715
Added by nagachika (Tomoyuki Chikanaga) over 1 year ago

merge revision(s) 54141,54542,54548: [Backport #12082]

test_optimization.rb: tailcall

* test/ruby/test_optimization.rb (TestRubyOptimization.tailcall):

helper method to compile methods with tailcall optimization
enabled.
* compile.c (iseq_optimize): disable tail call optimization in
rescued, rescue, and ensure blocks.
[Bug #12082]

* compile.c (new_label_body): initialize bit fields, since
  compile_data_alloc does not clear the memory.  [Bug #12082]

Revision 54799
Added by usa (Usaku NAKAMURA) over 1 year ago

  • compile.c (new_label_body): missed backporting r54548 in r54698. this fixes randomly test failure introduced by r54698. cf. [Bug #12082]

History

#1 [ruby-core:73873] Updated by ko1 (Koichi Sasada) over 1 year ago

  • Assignee set to ko1 (Koichi Sasada)

#2 [ruby-core:74240] Updated by rhenium (Kazuki Yamaguchi) over 1 year ago

Updating my patch, because it breaks such code:

def errinfo
  $!
end
RubyVM::InstructionSequence.compile(<<EOF, __FILE__, __FILE__, __LINE__, tailcall_optimization: true).eval
  def test_rescue
    raise "a"
  rescue
    errinfo
  end
EOF

p test_rescue # should return a RuntimeError

#4 [ruby-core:74874] Updated by ko1 (Koichi Sasada) over 1 year ago

Thank you for reporting and patches.

Nobu's patch seems good. Could you commit it?

#5 Updated by nobu (Nobuyoshi Nakada) over 1 year ago

  • Status changed from Open to Closed

Applied in changeset r54542.


compile.c: disable tco with rescue

  • compile.c (iseq_optimize): disable tail call optimization in rescued, rescue, and ensure blocks. [Bug #12082]

#6 [ruby-core:75103] Updated by usa (Usaku NAKAMURA) over 1 year ago

  • Backport changed from 2.0.0: UNKNOWN, 2.1: UNKNOWN, 2.2: UNKNOWN, 2.3: UNKNOWN to 2.1: WONTFIX, 2.2: REQUIRED, 2.3: REQUIRED

#7 [ruby-core:75120] Updated by usa (Usaku NAKAMURA) over 1 year ago

  • Backport changed from 2.1: WONTFIX, 2.2: REQUIRED, 2.3: REQUIRED to 2.1: WONTFIX, 2.2: DONE, 2.3: REQUIRED

ruby_2_2 r54698 merged revision(s) 54542,54548.

#8 [ruby-core:75142] Updated by nagachika (Tomoyuki Chikanaga) over 1 year ago

  • Backport changed from 2.1: WONTFIX, 2.2: DONE, 2.3: REQUIRED to 2.1: WONTFIX, 2.2: DONE, 2.3: DONE

ruby_2_3 r54715 merged revision(s) 54141,54542,54548.

Also available in: Atom PDF