summaryrefslogtreecommitdiff
path: root/eval_intern.h
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-11-04 01:08:21 (GMT)
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-11-04 01:08:21 (GMT)
commit2c101190e8fd20eb050f7e99243f874c30f3ea3a (patch)
treedaf0dbbae2dec8fd168d69400c39044367392403 /eval_intern.h
parent3566a762d2cc23807a6539940679b6f0edbe637b (diff)
eval_intern.h: avoid undefined behavior of setjmp
* eval_intern.h (TH_EXEC_TAG, TH_JUMP_TAG): get rid of undefined behavior of setjmp() in rhs of assignment expression. [ISO/IEC 9899:1999] 7.13.1.1 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@43522 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'eval_intern.h')
-rw-r--r--eval_intern.h27
1 files changed, 23 insertions, 4 deletions
diff --git a/eval_intern.h b/eval_intern.h
index 190ef91..b945848 100644
--- a/eval_intern.h
+++ b/eval_intern.h
@@ -108,14 +108,33 @@ extern int select_large_fdset(int, fd_set *, fd_set *, fd_set *, struct timeval
#define PUSH_TAG() TH_PUSH_TAG(GET_THREAD())
#define POP_TAG() TH_POP_TAG()
-#define TH_EXEC_TAG() ruby_setjmp(_th->tag->buf)
+/* clear th->state, and return the value */
+static inline int
+ruby_threadptr_tag_state(rb_thread_t *th)
+{
+ int state = th->state;
+ th->state = 0;
+ return state;
+}
+
+NORETURN(static inline void ruby_threadptr_tag_jump(rb_thread_t *, int));
+static inline void
+ruby_threadptr_tag_jump(rb_thread_t *th, int st)
+{
+ ruby_longjmp(th->tag->buf, (th->state = st));
+}
+
+/*
+ setjmp() in assignment expression rhs is undefined behavior
+ [ISO/IEC 9899:1999] 7.13.1.1
+*/
+#define TH_EXEC_TAG() \
+ (ruby_setjmp(_th->tag->buf) ? ruby_threadptr_tag_state(_th) : 0)
#define EXEC_TAG() \
TH_EXEC_TAG()
-#define TH_JUMP_TAG(th, st) do { \
- ruby_longjmp((th)->tag->buf,(st)); \
-} while (0)
+#define TH_JUMP_TAG(th, st) ruby_threadptr_tag_jump(th, st)
#define JUMP_TAG(st) TH_JUMP_TAG(GET_THREAD(), (st))