Bug #6701

once literal doesn't care escape

Added by Koichi Sasada almost 2 years ago. Updated 8 months ago.

[ruby-dev:45923]
Status:Closed
Priority:Normal
Assignee:Koichi Sasada
Category:core
Target version:next minor
ruby -v:ruby 2.0.0dev (2012-07-05 trunk 36311) [i386-mswin32_100] Backport:

Description

=begin

= 概要

/#{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)

=end

Associated revisions

Revision 42637
Added by Koichi Sasada 8 months 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.
  • vmcore.h: `union iseqinlinestorageentry' 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: ISEQMINORVERSION to 1 (should increment major?)

History

#1 Updated by Yusuke Endoh almost 2 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/show/2398

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

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

Yusuke Endoh mame@tsg.ne.jp

#2 Updated by Koichi Sasada over 1 year ago

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

#3 Updated by Koichi Sasada over 1 year ago

  • Target version changed from 2.0.0 to next minor

timeup.

#4 Updated by Koichi Sasada 8 months ago

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

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.
  • vmcore.h: `union iseqinlinestorageentry' 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: ISEQMINORVERSION to 1 (should increment major?)

Also available in: Atom PDF