summaryrefslogtreecommitdiff
path: root/cop.h
diff options
context:
space:
mode:
authorTony Cook <tony@develop-help.com>2022-09-06 15:37:41 +1000
committerTony Cook <tony@develop-help.com>2022-09-08 09:47:03 +1000
commitf9e2b18ffd509cec1aa73a663727330a02adff7d (patch)
treee86a5141b2a3ccaa3cc8eba7634576fb618148be /cop.h
parent88745cf76c5a2fcd907eec49427ee74a02e529b3 (diff)
downloadperl-f9e2b18ffd509cec1aa73a663727330a02adff7d.tar.gz
avoid undefined behavior when calling setjmp()
From the standard: "An invocation of the setjmp macro shall appear only in one of the following contexts: - the entire controlling expression of a selection or iteration statement; - one operand of a relational or equality operator with the other operand an integer constant expression, with the resulting expression being the entire controlling expression of a selection or iteration statement; - the operand of a unary ! operator with the resulting expression being the entire controlling expression of a selection or iteration statement; or - the entire expression of an expression statement (possibly cast to void). If the invocation appears in any other context, the behavior is undefined." which does not include assignment. Fixes #20189
Diffstat (limited to 'cop.h')
-rw-r--r--cop.h14
1 files changed, 12 insertions, 2 deletions
diff --git a/cop.h b/cop.h
index 120067d624..cb30e5feeb 100644
--- a/cop.h
+++ b/cop.h
@@ -121,7 +121,15 @@ typedef struct jmpenv JMPENV;
}); \
cur_env.je_prev = PL_top_env; \
JE_OLD_STACK_HWM_save(cur_env); \
- cur_env.je_ret = PerlProc_setjmp(cur_env.je_buf, SCOPE_SAVES_SIGNAL_MASK); \
+ /* setjmp() is callable in limited contexts which does not */ \
+ /* include assignment, so switch() instead */ \
+ switch (PerlProc_setjmp(cur_env.je_buf, SCOPE_SAVES_SIGNAL_MASK)) { \
+ case 0: cur_env.je_ret = 0; break; \
+ case 1: cur_env.je_ret = 1; break; \
+ case 2: cur_env.je_ret = 2; break; \
+ case 3: cur_env.je_ret = 3; break; \
+ default: Perl_croak(aTHX_ "panic: unexpected setjmp() result\n"); \
+ } \
JE_OLD_STACK_HWM_restore(cur_env); \
PL_top_env = &cur_env; \
cur_env.je_mustcatch = FALSE; \
@@ -155,8 +163,10 @@ typedef struct jmpenv JMPENV;
while (p) { i++; p = p->je_prev; } \
Perl_deb(aTHX_ "JMPENV_JUMP(%d) level=%d in %s at %s:%d\n", \
(int)(v), i, SAFE_FUNCTION__, __FILE__, __LINE__);}) \
- if (PL_top_env->je_prev) \
+ if (PL_top_env->je_prev) { \
+ assert((v) >= 0 && (v) <= 3); \
PerlProc_longjmp(PL_top_env->je_buf, (v)); \
+ } \
if ((v) == 2) \
PerlProc_exit(STATUS_EXIT); \
PerlIO_printf(PerlIO_stderr(), "panic: top_env, v=%d\n", (int)(v)); \