Bug #6701
closedonce literal doesn't care escape
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)
Updated by mame (Yusuke Endoh) over 12 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
Updated by ko1 (Koichi Sasada) almost 12 years ago
これ,preview 2 の後でも許されますか?
許されないなら next minor 行き.
Updated by ko1 (Koichi Sasada) about 11 years 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 introduce
once' instruction.
once' doesn't use
setinlinecache' 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 on
onceinlinecache' insn. - test/ruby/test_regexp.rb: add tests.
- iseq.c: ISEQ_MINOR_VERSION to 1 (should increment major?)
Updated by nobu (Nobuyoshi Nakada) over 9 years ago
- Related to Feature #11026: How atomic should dynamic regexp with "once" flag be? added