著作一覧 |
YARVの動きに詳しい方、助言をお願いします。
以下、状況を手短に説明。
ASRのテストをしていたら、イベントハンドラ付きのテキストを設定するところでエラーとなる。
たとえば以下のコード
Window.document.getElementById('foo').innerHTML = '<div id="x" onclick="funcall()">hello</div>'
この呼び出しを行うと、次の動作をする。スレッドは2つある。1つはMSHTAのスレッド、もう1つはRubyのスレッドだ。それぞれスレッドMとスレッドRとする。
_unk = Proc.new { funcall() }
(スレッドM)これは困った。Ruby-1.8.7では特に問題なかったのだが。
原因は、おそらくWin32OLE#method_missing呼び出し中(innerHTML=メソッドの呼び出し)の再入にあるのだろう。
この時のスレッドRのスタックトレースは以下となる。
cfp->iseq == 0 直前のcfp cfp->iseq = 0 cfp->flag 0x0061 (& VM_FRAME_FLAG_PASSED == 0) vm_get_ruby_level_caller_cfp(rb_thread_struct * 0x001b6ff0, rb_control_frame_t * 0x029bfed0) line 152 eval_string_with_cref(unsigned long 0x02f23cc4, unsigned long 0x02fff1e8, unsigned long 0x00000004, RNode * 0x02fff1c0, const char * 0x03000518, int 0x00000000) line 707 + 16 bytes eval_under(unsigned long 0x02f23c60, unsigned long 0x02f23cc4, unsigned long 0x02fff1e8, const char * 0x03000518, int 0x00000000) line 941 + 27 bytes specific_eval(int 0x00000003, unsigned long * 0x032dc934, unsigned long 0x02f23c60, unsigned long 0x02f23cc4) line 979 + 27 bytes rb_obj_instance_eval(int 0x00000003, unsigned long * 0x032dc934, unsigned long 0x02f23cc4) line 1017 + 21 bytes call_cfunc(unsigned long (void)* 0x02c394a0 rb_obj_instance_eval(int, unsigned long *, unsigned long), unsigned long 0x02f23cc4, int 0xffffffff, int 0x00000003, const unsigned long * 0x032dc934) line 286 + 15 bytes vm_call0(rb_thread_struct * 0x001b6ff0, unsigned long 0x02f4bf44, unsigned long 0x02f23cc4, unsigned long 0x00000ad0, unsigned long 0x00000ad0, int 0x00000003, const unsigned long * 0x032dc934, const RNode * 0x02f449b0, int 0x00000000) line 71 + 31 bytes rb_funcall2(unsigned long 0x02f23cc4, unsigned long 0x00000ad0, int 0x00000003, const unsigned long * 0x032dc934) line 412 + 1290 bytes safe_funcall(unsigned long 0x032dc92c) line 142 + 27 bytes rb_protect(unsigned long (unsigned long)* 0x10034840 safe_funcall(unsigned long), unsigned long 0x032dc92c, int * 0x032dc940) line 647 + 31 bytes CRubyWrapper::rb_funcall_with_string2(CRubyWrapper * const 0x030610f8, IRubyEngine * 0x03063ac8, unsigned long 0x02f23cc4, unsigned long 0x00000ad0, long 0x00000000, long 0x00000029, unsigned char * 0x0056834c, unsigned char 0x00, tagVARIANT * 0x032dcbc8 {VT_EMPTY}, IActiveScriptError * * 0x00571e90) line 243 + 18 bytes RPCRT4! 75ee43b6() RPCRT4! 75f70cc6() RPCRT4! 75f7093e() <----LRPCによってスレッドMから再入 OLE32! 77389759() OLE32! 773896f3() OLE32! 772a9d67() OLE32! 772a9c5c() OLE32! 772aaab0() OLE32! 7738961b() OLE32! 77389498() OLE32! 77389aa2() OLE32! 772aa8ea() OLE32! 772aa8a9() USER32! 763a8807() USER32! 763a8962() USER32! 763a8aad() USER32! 763a8b00() OLE32! 7727b0a6() OLE32! 77278a9d() OLE32! 772789d7() OLE32! 7727898f() OLE32! 7727ac88() OLE32! 7727ad74() OLE32! 77387c28() OLE32! 773889d4() OLE32! 7727ad2e() OLE32! 7727ace0() OLE32! 7729e688() RPCRT4! 75f71074() <--- LRPCでスレッドMのDOM操作 RPCRT4! 75f7102b() DISPEX! 727f2576() DISPEX! 727f2a43() CRScriptCore::fole_propertyput(unsigned long 0x001b85dc, unsigned long 0x02fff1fc, unsigned long 0x02fff210) line 866 + 54 bytes CRScriptCore::foleex_missing(int 0x00000002, unsigned long * 0x032ddf60, unsigned long 0x001b85dc) line 1233 + 22 bytes call_cfunc(unsigned long (void)* 0x100012b2 CRScriptCore::foleex_missing(int,unsigned long *,unsigned long), unsigned long 0x001b85dc, int 0xffffffff, int 0x00000002, const unsigned long * 0x032ddf60) line 286 + 15 bytes vm_call0(rb_thread_struct * 0x001b6ff0, unsigned long 0x02f23ecc, unsigned long 0x001b85dc, unsigned long 0x00000188, unsigned long 0x00000188, int 0x00000002, const unsigned long * 0x032ddf60, const RNode * 0x02f23e54, int 0x00000000) line 71 + 31 bytes rb_funcall2(unsigned long 0x001b85dc, unsigned long 0x00000188, int 0x00000002, const unsigned long * 0x032ddf60) line 412 + 1290 bytes vm_method_missing(rb_thread_struct * 0x001b6ff0, unsigned long 0x000031e4, unsigned long 0x001b85dc, int 0x00000001, rb_block_struct * 0x00000000, int 0x00000000) line 418 + 25 bytes vm_exec_core(rb_thread_struct * 0x001b6ff0, unsigned long 0x00000000) line 999 + 1881 bytes vm_exec(rb_thread_struct * 0x001b6ff0) line 1077 + 13 bytes rb_vm_invoke_proc(rb_thread_struct * 0x001b6ff0, rb_proc_t * 0x02fd9460, unsigned long 0x02f23cc4, int 0x00000001, const unsigned long * 0x032def50, rb_block_struct * 0x00000000) line 571 + 1117 bytes proc_call(int 0x00000001, unsigned long * 0x032def50, unsigned long 0x001b87d0) line 525 + 33 bytes call_cfunc(unsigned long (void)* 0x02c9cb30 proc_call(int, unsigned long *, unsigned long), unsigned long 0x001b87d0, int 0xffffffff, int 0x00000001, const unsigned long * 0x032def50) line 286 + 15 bytes vm_call0(rb_thread_struct * 0x001b6ff0, unsigned long 0x02f2f628, unsigned long 0x001b87d0, unsigned long 0x000015a0, unsigned long 0x000015a0, int 0x00000001, const unsigned long * 0x032def50, const RNode * 0x02f2f5b0, int 0x00000000) line 71 + 31 bytes rb_funcall2(unsigned long 0x001b87d0, unsigned long 0x000015a0, int 0x00000001, const unsigned long * 0x032def50) line 412 + 1290 bytes CRubyWrapper::InvokeRuby(unsigned long 0x032def40) line 513 + 33 bytes rb_protect(unsigned long (unsigned long)* 0x10001af0 CRubyWrapper::InvokeRuby(unsigned long), unsigned long 0x032def40, int * 0x032defb0) line 647 + 31 bytes CRubyWrapper::rb_invoke(CRubyWrapper * const 0x030610f8, IRubyEngine * 0x03063ac8, unsigned long 0x001b87d0, unsigned long 0x000015a0, tagDISPPARAMS * 0x0056f9b8, tagVARIANT * 0x005975d0 {VT_EMPTY}, IActiveScriptError * * 0x00597608) line 346 + 18 bytes RPCRT4! 75ee43b6() RPCRT4! 75f70cc6() RPCRT4! 75f7093e() <--- LRPCでスレッドRからASRのCOM wrapper経由でinstance_evalが呼ばれる OLE32! 77389759() OLE32! 773896f3() OLE32! 772a9d67() OLE32! 772a9c5c() OLE32! 772aaab0() OLE32! 7738961b() OLE32! 77389498() OLE32! 77389aa2() OLE32! 772aa8ea() OLE32! 772aa8a9() USER32! 763a8807() USER32! 763a8962() USER32! 763a8aad() USER32! 763a8b00() RubyWrapper(void * 0x0033e694) line 141 + 12 bytes _threadstartex(void * 0x03063f20) line 227 + 13 bytes <--- 本当のトップレベル KERNEL32! 7743e3f3() NTDLL! 77cecfed() NTDLL! 77ced1ff()
途中でLRPCやOLEがスタックを変えてはいるが、YARVのフレームやスレッドを破壊しているわけではない(実際、thおよびcfpはASRのinstance_eval呼び出し時はWin32OLE#method_missingの時のものを取り出している。したがって状態はcall_cfunc中にcall_cfuncされた状態だと思える、というかどういう状態が正しいのかYARVを読み切れていない)。
c呼び出しが重なるのが原因かと思って小さな再現プログラムを作ったが、その方法では再現しない。
ジェズイットを見習え |