diff options
author | Tony Cook <tony@develop-help.com> | 2022-09-06 15:37:41 +1000 |
---|---|---|
committer | Tony Cook <tony@develop-help.com> | 2022-09-08 09:47:03 +1000 |
commit | f9e2b18ffd509cec1aa73a663727330a02adff7d (patch) | |
tree | e86a5141b2a3ccaa3cc8eba7634576fb618148be /cop.h | |
parent | 88745cf76c5a2fcd907eec49427ee74a02e529b3 (diff) | |
download | perl-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.h | 14 |
1 files changed, 12 insertions, 2 deletions
@@ -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)); \ |