Project

General

Profile

Bug #12082

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

Added by rhenium (Kazuki Yamaguchi) over 4 years ago. Updated about 4 years 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.


Files

Updated by ko1 (Koichi Sasada) over 4 years ago

  • Assignee set to ko1 (Koichi Sasada)

Updated by rhenium (Kazuki Yamaguchi) about 4 years 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

Updated by ko1 (Koichi Sasada) about 4 years ago

Thank you for reporting and patches.

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

#5

Updated by nobu (Nobuyoshi Nakada) about 4 years 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. [ruby-core:73871] [Bug #12082]

Updated by usa (Usaku NAKAMURA) about 4 years 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

Updated by usa (Usaku NAKAMURA) about 4 years 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.

Updated by nagachika (Tomoyuki Chikanaga) about 4 years 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