From: Motohiro KOSAKI Date: 2011-04-30T17:33:22+09:00 Subject: [ruby-dev:43460] [Ruby 1.9 - Bug #4636][Open]thread.c#do_select() が HAVE_RB_FD_INIT のケースを正しくハンドリングしていない Issue #4636 has been reported by Motohiro KOSAKI. ---------------------------------------- Bug #4636: thread.c#do_select() が HAVE_RB_FD_INIT のケースを正しくハンドリングしていない http://redmine.ruby-lang.org/issues/4636 Author: Motohiro KOSAKI Status: Open Priority: Low Assignee: Motohiro KOSAKI Category: core Target version: 1.9.3 ruby -v: ruby 1.9.3dev (2011-04-30 trunk 31387) [x86_64-linux] えっと。気づいたので起票しておきます do_select()に fd_set UNINITIALIZED_VAR(orig_read); .... if (read) orig_read = *read; なんて行がありますが、これはあからさまに間違っていて、たとえば最近のBSDだと http://netbsd.gw.com/cgi-bin/man-cgi?select++NetBSD-4.0 fd_set *fdsr; int max = fd; fdsr = (fd_set *)calloc(howmany(max+1, NFDBITS), sizeof(fd_mask)); if (fdsr == NULL) { ... return (-1); } FD_SET(fd, fdsr); n = select(max+1, fdsr, NULL, NULL, &tv); ... free(fdsr); みたいに、動的にallocateしているので実際の配列長はfd_setの定義よりも大きいことはよくあります。なので、fd_setは*でdereferenceしちゃダメです。たぶんいままで踏まなかったのは NFILE limitを あげてテストする人が少ないんでしょう。 対策としては、thread.c で fd_set* 引数とってるところを全部 rb_fd_set_t* に 差し替えて rb_fd_copy() でコピーするようにしたらいいんじゃないでしょうか このバグは以下のコミットで混入したようです。 commit ae317b518c4dcbcbf0ed02bb9e6cd7513f0a34fe Author: ko1 Date: Thu Feb 8 11:51:40 2007 +0000 * thread.c: change GVL_UNLOCK_RANGE() arguments (adding ubf as 2nd argument). * thread.c: fix to use polling in select on cygwin and mswin32. (snip) -- http://redmine.ruby-lang.org