Variables set before setjmp and read afterwards must be set as volatile, otherwise the compiler can load them into registers where longjmp will clobber them. Recent versions of clang on AMD64 do not reload the cfp variable in rb_protect otherwise. --- eval.c.orig 2015-11-16 14:50:49.000000000 +0000 +++ eval.c @@ -743,7 +743,7 @@ rb_rescue2(VALUE (* b_proc) (ANYARGS), V { int state; rb_thread_t *th = GET_THREAD(); - rb_control_frame_t *cfp = th->cfp; + rb_control_frame_t *volatile cfp = th->cfp; volatile VALUE result = Qfalse; volatile VALUE e_info = th->errinfo; va_list args; @@ -809,7 +809,7 @@ rb_protect(VALUE (* proc) (VALUE), VALUE volatile VALUE result = Qnil; volatile int status; rb_thread_t *th = GET_THREAD(); - rb_control_frame_t *cfp = th->cfp; + rb_control_frame_t * volatile cfp = th->cfp; struct rb_vm_protect_tag protect_tag; rb_jmpbuf_t org_jmpbuf; --- eval_error.c.orig 2015-11-16 15:02:19.000000000 +0000 +++ eval_error.c @@ -80,9 +80,9 @@ static void error_print(void) { volatile VALUE errat = Qundef; - rb_thread_t *th = GET_THREAD(); - VALUE errinfo = th->errinfo; - int raised_flag = th->raised_flag; + rb_thread_t * volatile th = GET_THREAD(); + volatile VALUE errinfo = th->errinfo; + volatile int raised_flag = th->raised_flag; volatile VALUE eclass = Qundef, e = Qundef; const char *volatile einfo; volatile long elen; --- thread.c.orig 2015-11-16 15:03:41.000000000 +0000 +++ thread.c @@ -420,8 +420,8 @@ rb_threadptr_unlock_all_locking_mutexes( void rb_thread_terminate_all(void) { - rb_thread_t *th = GET_THREAD(); /* main thread */ - rb_vm_t *vm = th->vm; + rb_thread_t *volatile th = GET_THREAD(); /* main thread */ + rb_vm_t *volatile vm = th->vm; if (vm->main_thread != th) { rb_bug("rb_thread_terminate_all: called by child thread (%p, %p)", --- vm_eval.c.orig 2015-11-16 14:55:47.000000000 +0000 +++ vm_eval.c @@ -1062,7 +1062,7 @@ rb_iterate(VALUE (* it_proc) (VALUE), VA int state; volatile VALUE retval = Qnil; NODE *node = NEW_IFUNC(bl_proc, data2); - rb_thread_t *th = GET_THREAD(); + rb_thread_t * volatile th = GET_THREAD(); rb_control_frame_t *volatile cfp = th->cfp; node->nd_aid = rb_frame_this_func(); @@ -1190,7 +1190,7 @@ eval_string_with_cref(VALUE self, VALUE int state; VALUE result = Qundef; VALUE envval; - rb_thread_t *th = GET_THREAD(); + rb_thread_t *volatile th = GET_THREAD(); rb_env_t *env = NULL; rb_block_t block, *base_block; volatile int parse_in_eval; @@ -1843,8 +1843,8 @@ rb_catch_protect(VALUE t, rb_block_call_ { int state; volatile VALUE val = Qnil; /* OK */ - rb_thread_t *th = GET_THREAD(); - rb_control_frame_t *saved_cfp = th->cfp; + rb_thread_t * volatile th = GET_THREAD(); + rb_control_frame_t * volatile saved_cfp = th->cfp; volatile VALUE tag = t; TH_PUSH_TAG(th); --- vm_trace.c.orig 2015-11-16 15:02:00.000000000 +0000 +++ vm_trace.c @@ -390,7 +390,7 @@ rb_suppress_tracing(VALUE (*func)(VALUE) volatile int raised; volatile int outer_state; VALUE result = Qnil; - rb_thread_t *th = GET_THREAD(); + rb_thread_t * volatile th = GET_THREAD(); int state; const int tracing = th->trace_arg ? 1 : 0; rb_trace_arg_t dummy_trace_arg;