Project

General

Profile

Bug #6701

once literal doesn't care escape

Added by Koichi Sasada almost 4 years ago. Updated about 1 year ago.

Status:
Closed
Priority:
Normal
Assignee:
ruby -v:
ruby 2.0.0dev (2012-07-05 trunk 36311) [i386-mswin32_100]
Backport:
[ruby-dev:45923]

Description

概要

/#{expr}/o は,expr はたかだか一回しか実行されない,後から評価したときは expr の評価値(を用いた正規表現)が返されるという意味になります.しかし,expr 中で例外などで大域脱出が発生し,再度評価しようとすると,まだ expr は実行中であると認識されるため,ブロックします.

現象

次のようなコードが止まりません.

  2.times{
    catch(:escape){
      p:before
      r = /#{throw :escape}/o
      # まだ,1度目の処理が終わってないとみなされているため,
      # 2回目に実行しようとすると,その1度目の終了を待つ
      # (もちろん,1度目は throw によって cancel されている→デッドロック)
      p:after
    }
  }

スレッドを絡めるとこんな感じです.

  (1..2).map{
    Thread.new{
      begin
        r = /#{raise}/o
        # あるスレッドが実行しようとするが,例外でキャンセルされる
        # 別のスレッドは,キャンセルされた実行の終了を待つ
        # (もちろん,終わるわけがないのでデッドロック)
      rescue
        p :raised
      ensure
        p :exit
      end
    }
  }.each{|t| t.join}

修正案

expr が例外でキャンセルされたら,ちゃんと「未実行状態」に戻して,待ってるスレッドがいればそのスレッドが expr をやり直すべきではないかと思います.具体的には,ちゃんと ensure 的な処理を入れる様に改造します.

特に何も意見がなければ,2.0 はこの方針で直します.

1.9 は,もうこのまま,でしょうか.これまで文句が来たことが無いので,誰も /#{expr}/o なんて使ってないってことですかね.

別の選択肢として,例外で抜けたら expr の評価値を nil にする,という案もありますが,なぜ nil なのか,とかあまり説得力のある理由が思いつきません.

余談

ところで,これを考えていて,次の様な例が思い当たりました.

  def foo
    r = /#{foo}/o
  end

  foo

これ,どうするべきなんだろう.こんなこと書くな,でしょうか.それとも,deadlock というか,recursive な once なのでエラー,とするのがいいでしょうか(エラーがいい気がするな).

ちなみに,1.8 だと問答無用で実行しちゃうようで:

  t.rb:3:in `foo': stack level too deep (SystemStackError)

Related issues

Related to CommonRuby - Feature #11026: How atomic should dynamic regexp with "once" flag be? Open

Associated revisions

Revision 42637
Added by Koichi Sasada over 2 years ago

  • insns.def: fix regexp's once option behavior. fix [ruby-trunk - Bug #6701]
  • insns.def: remove onceinlinecache' and introduceonce' instruction. once' doesn't usesetinlinecache' insn any more.
  • vm_core.h: `union iseq_inline_storage_entry' to store once data.
  • compile.c: catch up above changes.
  • iseq.c: ditto.
  • vm.c, vm_insnhelper.c: ditto. fix m_core_set_postexe()' which is depend ononceinlinecache' insn.
  • test/ruby/test_regexp.rb: add tests.
  • iseq.c: ISEQ_MINOR_VERSION to 1 (should increment major?)

Revision 42637
Added by Koichi Sasada over 2 years ago

  • insns.def: fix regexp's once option behavior. fix [ruby-trunk - Bug #6701]
  • insns.def: remove onceinlinecache' and introduceonce' instruction. once' doesn't usesetinlinecache' insn any more.
  • vm_core.h: `union iseq_inline_storage_entry' to store once data.
  • compile.c: catch up above changes.
  • iseq.c: ditto.
  • vm.c, vm_insnhelper.c: ditto. fix m_core_set_postexe()' which is depend ononceinlinecache' insn.
  • test/ruby/test_regexp.rb: add tests.
  • iseq.c: ISEQ_MINOR_VERSION to 1 (should increment major?)

Revision 42637
Added by Koichi Sasada over 2 years ago

  • insns.def: fix regexp's once option behavior. fix [ruby-trunk - Bug #6701]
  • insns.def: remove onceinlinecache' and introduceonce' instruction. once' doesn't usesetinlinecache' insn any more.
  • vm_core.h: `union iseq_inline_storage_entry' to store once data.
  • compile.c: catch up above changes.
  • iseq.c: ditto.
  • vm.c, vm_insnhelper.c: ditto. fix m_core_set_postexe()' which is depend ononceinlinecache' insn.
  • test/ruby/test_regexp.rb: add tests.
  • iseq.c: ISEQ_MINOR_VERSION to 1 (should increment major?)

History

#1 [ruby-dev:45924] Updated by Yusuke Endoh almost 4 years ago

  • Status changed from Open to Assigned

遠藤です。

2012年7月5日 19:02 ko1 (Koichi Sasada) redmine@ruby-lang.org:

しかし,expr 中で例外などで大域脱出が発生し,再度評価しようとすると,まだ expr は実行中であると認識されるため,ブロックします.

この問題は認識してましたが、以下の通りサボってました。

http://bugs.ruby-lang.org/issues/2398

特に何も意見がなければ,2.0 はこの方針で直します.

賛成です。直してください。

--
Yusuke Endoh mame@tsg.ne.jp

#2 [ruby-dev:46623] Updated by Koichi Sasada over 3 years ago

これ,preview 2 の後でも許されますか?
許されないなら next minor 行き.

#3 [ruby-dev:46774] Updated by Koichi Sasada over 3 years ago

  • Target version changed from 2.0.0 to next minor

timeup.

#4 Updated by Koichi Sasada over 2 years ago

  • % Done changed from 0 to 100
  • Status changed from Assigned to Closed

This issue was solved with changeset r42637.
Koichi, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.


  • insns.def: fix regexp's once option behavior. fix [ruby-trunk - Bug #6701]
  • insns.def: remove onceinlinecache' and introduceonce' instruction. once' doesn't usesetinlinecache' insn any more.
  • vm_core.h: `union iseq_inline_storage_entry' to store once data.
  • compile.c: catch up above changes.
  • iseq.c: ditto.
  • vm.c, vm_insnhelper.c: ditto. fix m_core_set_postexe()' which is depend ononceinlinecache' insn.
  • test/ruby/test_regexp.rb: add tests.
  • iseq.c: ISEQ_MINOR_VERSION to 1 (should increment major?)

#5 Updated by Nobuyoshi Nakada about 1 year ago

  • Related to Feature #11026: How atomic should dynamic regexp with "once" flag be? added

#6 Updated by Nobuyoshi Nakada about 1 year ago

  • Description updated (diff)

Also available in: Atom PDF