Project

General

Profile

Bug #2398

race condition of /#{ foo }/o

Added by mame (Yusuke Endoh) about 9 years ago. Updated over 7 years ago.

Status:
Closed
Priority:
Normal
Target version:
ruby -v:
-
Backport:
[ruby-dev:39768]

Description

=begin
遠藤です。

以下のようにすると SEGV します。

$ cat race.rb
f = proc {|s| /#{ sleep 1; s }/o }
[ Thread.new { f.call("foo"); nil },
Thread.new { sleep 0.5; f.call("bar"); nil },
].each {|t| t.join }
GC.start
p f.call

$ ./ruby race.rb
race.rb:6: [BUG] Segmentation fault
ruby 1.9.2dev (2009-11-24 trunk 25908) [i686-linux]

-- control frame ----------
c:0004 p:---- s:0011 b:0011 l:000010 d:000010 CFUNC :p
c:0003 p:0083 s:0007 b:0007 l:001d8c d:0022e8 EVAL race.rb:6
c:0002 p:---- s:0004 b:0004 l:000003 d:000003 FINISH
c:0001 p:0000 s:0002 b:0002 l:001d8c d:001d8c TOP


race.rb:6:in <main>'
race.rb:6:in
p'

セグメンテーション違反です

onceinlinecache を通ってから setinlinecache に着く前までの間
(= /#{ sleep 1; s }/o の評価が始まってから終わるまでの間) に
複数のスレッドが突入すると、インラインキャッシュのアクセスが
race condition になっていて適切にマークされなくなるようです。

解決方法としては、当該範囲がクリティカルセクションになるよう
同期を行うか、または何かをする必要があると思います。

once フラグのある正規表現を複数スレッドで同時に評価した場合の
意味はどうなるでしょうか。

--
Yusuke ENDOH mame@tsg.ne.jp
=end

History

#1

Updated by ujihisa (Tatsuhiro Ujihisa) about 9 years ago

  • Status changed from Open to Assigned
  • Assignee set to nobu (Nobuyoshi Nakada)

=begin

=end

#2

Updated by mame (Yusuke Endoh) over 8 years ago

  • Assignee changed from nobu (Nobuyoshi Nakada) to mame (Yusuke Endoh)
  • Target version set to 1.9.2
  • ruby -v set to -

=begin
遠藤です。

とりあえず、最初に once 区間に突入した (onceinlinecache を実行した)
スレッドが once 区間を脱出する (setinlinecache を実行する) まで、
2 番目以降に同じ区間に突入するスレッドをブロックするパッチを書きま
した。

最初のスレッドが正常に出口に到達しなかった場合、2 番目以降に突入した
スレッドたちは永久にブロックしてしまいますが、SEGV よりましですし、
Ctrl+C で止めることもできるので、いいかなと思います。
そもそもそういう状況になるようなプログラムに問題があると言えるかも
しれません。

すぐにコミットしてしまいますが、反対があったら言ってください。

diff --git a/insns.def b/insns.def
index 9541465..ba6f1d6 100644
--- a/insns.def
+++ b/insns.def
@@ -1199,10 +1199,17 @@ onceinlinecache
()
(VALUE val)
{

  • retry: if (ic->ic_vmstat) { val = ic->ic_value.value; JUMP(dst); }
  • else if (ic->ic_value.value == Qundef)
  • {
  • RUBY_VM_CHECK_INTS();
  • rb_thread_schedule();
  • goto retry;
  • } else { /* none */ ic->ic_value.value = Qundef;

--
Yusuke Endoh mame@tsg.ne.jp
=end

#3

Updated by mame (Yusuke Endoh) over 8 years ago

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

=begin
This issue was solved with changeset r27515.
Yusuke, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.

=end

Also available in: Atom PDF