rb_block_given_p を調べたときのメモ

ruby 1.9.2 と tokyocabinet の ruby binding が動かない

ruby 1.9.2 と tokyocabinet の ruby binding の 1.29 を使っていると HDB#each などが動かない。 ブロックを与えているのだが「no block given」となる。 tokyocabinet の ruby binding のソースを見ると

if(rb_block_given_p() != Qtrue) rb_raise(rb_eArgError, "no block given");

の部分でエラーが起きているようだ。

ruby のソースコードを取得する

git clone https://github.com/ruby/ruby.git

でソースコードを取得する。

GNU GLOBAL

gtags -v

としてタグを作る。

GPATH  GPL  GRTAGS  GSYMS  GTAGS

ができる。

global rb_block_given_p

とすると

eval.c

と表示される。rb_block_given_p は eval.c で定義されていることがわかる。

rb_block_given_p を実行してみる

rb_block_given_p を実行する簡単なプログラムを作って調べる。 以下の 3 つのファイルを同じディレクトリを作成する。

extconf.rb

require 'mkmf'

create_makefile("block_given")

test_block_given.c

#include <ruby.h>

static VALUE block_given_test (VALUE self)
{
  return rb_block_given_p();
}

void Init_block_given(){
  VALUE block_given_class;
  block_given_class = rb_define_class("TestBlockGiven", rb_cObject);
  rb_define_method(block_given_class, "block_given_test", block_given_test, 0);
}

test.rb

require_relative './block_given'

test = TestBlockGiven.new
p test.block_given_test { |a| a }

実行する

ruby extconf.rb
make
ruby test.rb

とすると

0

と表示される。

rb_block_given_p() != Qtrue

だとすると true や false を返すはずなのだが、 どうも rb_block_given_p の返り値が変更されたようだ。

rb_block_given_p の変更を調べる

eval.c の 613 〜 625 行で rb_block_given_p が定義されているので

git blame -L 613,625 eval.c

として各行がどのコミットから来ているのかを調べる。

e07cb859 (nobu 2009-07-18 08:05:32 +0000 620)   return TRUE;

となっているので rb_block_given_p は「e07cb859」から来ていることが分かる。

git show e07cb859

でそのコミットを調べる。

@@ -534,10 +536,10 @@ rb_block_given_p(void)

     if ((th->cfp->lfp[0] & 0x02) == 0 &&
        GC_GUARDED_PTR_REF(th->cfp->lfp[0])) {
-       return Qtrue;
+       return TRUE;
     }
     else {
-       return Qfalse;
+       return FALSE;
     }
 }

から返り値が Qtrue、Qfalse から TRUE、FALSE に変更されたことがわかる。 ruby 1.9.2 ではこの変更によって tokyocabinet の ruby binding が うまく動かなくなったことがわかった。

ruby 1.8.7 でどうなっているかは

git show origin/ruby_1_8_7:eval.c

を調べれば分かる。 1.8.7 では変更されていなかった。

tokyocabinet ruby binding の修正

単に 1.9.2 で動くようにするには tokyocabinet ruby binding の tokyocabinet.c で

rb_block_given_p() != Qtrue

!rb_block_given_p()

に変更する。

Tags of current page

,