From: Alex Budovski Date: 2015-07-23T01:22:55-07:00 Subject: [ruby-core:70097] rb_ensure and setjmp buffers AV on Win32 Hi all, I'm trying a trivial example calling void* node = rb_load_file(file); where 'file' intentionally doesn't exist. (Just to test graceful error handling) I get an AV (segfault) consistently. The AV was due to the following sequence of events, all revolving around rb_ensure. 1. PUSH_TAG(); creates a local _tag on the stack, and sets th->tag to its address. 2. EXEC_TAG(); calls setjmp on this _tag object 3. result = (*b_proc) (data1); fails with LoadError (calls load_file_internal with a nonexistent file, intentionally), setting state to 6. 4. POP_TAG(); resets th->tag to NULL. 5. if (state) JUMP_TAG(state); executes, looks up the current thread, and tries to jump to ruby_longjmp(th->tag->buf, 1); but th->tag is NULL, due to (4) above! So we AV when trying to get th->tag->buf. (68e4.20a4): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. *** WARNING: Unable to verify checksum for E:\dev\dbgscript\build\x64\Debug\x64-msvcr120-ruby230.dll MSVCR120!longjmp+0x12: 00007fff`c7c470c2 4c3911 cmp qword ptr [rcx],r10 ds:00000000`00000010=???????????????? 0:004> k # Child-SP RetAddr Call Site 00 0000008f`0d8ac890 00007fff`9e6a8dc7 MSVCR120!longjmp+0x12 [f:\dd\vctools\crt\crtw32\misc\amd64\longjmp.asm @ 82] 01 0000008f`0d8acdd0 00007fff`9e6a782e x64_msvcr120_ruby230!rb_threadptr_tag_jump+0x37 [e:\dev\ruby\eval_intern.h @ 163] 02 0000008f`0d8ace00 00007fff`9e6a18b5 x64_msvcr120_ruby230!rb_ensure+0x17e [e:\dev\ruby\eval.c @ 915] 03 0000008f`0d8acfb0 00007fff`9e6a124d x64_msvcr120_ruby230!load_file+0x65 [e:\dev\ruby\ruby.c @ 1779] 04 0000008f`0d8ad010 00007fff`9e6a11f2 x64_msvcr120_ruby230!rb_load_file_str+0x4d [e:\dev\ruby\ruby.c @ 1794] 05 0000008f`0d8ad0e0 00007fff`cd15122f x64_msvcr120_ruby230!rb_load_file+0x22 [e:\dev\ruby\ruby.c @ 1786] 06 0000008f`0d8ad120 00007fff`d14fc65f dbgscript!runscript+0x9f [e:\dev\dbgscript\src\dllmain.cpp @ 118] // other frames omitted VALUE rb_ensure(VALUE (*b_proc)(ANYARGS), VALUE data1, VALUE (*e_proc)(ANYARGS), VALUE data2) { int state; volatile VALUE result = Qnil; volatile VALUE errinfo; rb_thread_t *const th = GET_THREAD(); rb_ensure_list_t ensure_list; ensure_list.entry.marker = 0; ensure_list.entry.e_proc = e_proc; ensure_list.entry.data2 = data2; ensure_list.next = th->ensure_list; th->ensure_list = &ensure_list; PUSH_TAG(); if ((state = EXEC_TAG()) == 0) { result = (*b_proc) (data1); } POP_TAG(); errinfo = th->errinfo; th->ensure_list=ensure_list.next; (*ensure_list.entry.e_proc)(ensure_list.entry.data2); th->errinfo = errinfo; if (state) JUMP_TAG(state); return result; } Can someone explain how this is supposed to work?