diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2016-04-08 06:42:26 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2016-04-08 06:42:26 -0700 |
commit | 58bea998f5e5581ba8568dd83c4bebf883fabf76 (patch) | |
tree | 590036140a855386871c62e32b1d8c00679bcc45 /unwind.c | |
parent | cf4fe3baa5208bb84c956efd0d4eb1e4465c55f0 (diff) | |
download | txr-58bea998f5e5581ba8568dd83c4bebf883fabf76.tar.gz txr-58bea998f5e5581ba8568dd83c4bebf883fabf76.tar.bz2 txr-58bea998f5e5581ba8568dd83c4bebf883fabf76.zip |
New frame type to block bad unwinding and cont capture.
If some external function is invoked which can call back
into TXR Lisp, we should guard against the called-back
code from capturing a continuation across the external
stack frames, and also from unwinding across those
frames. This patch prepares a mechanism for this.
* unwind.c (uw_unwind_to_exit_point): Abort with message on
standard error if attempt is made to unwind across UW_GUARD
frame.
(uw_push_guard): New function.
(uw_capture_cont): If the frame search
encounters a UW_GUARD block, an exception is thrown.
* unwind.h (enum uw_frtype): New enum constant, UW_GUARD.
(uw_push_guard): Declared.
Diffstat (limited to 'unwind.c')
-rw-r--r-- | unwind.c | 33 |
1 files changed, 30 insertions, 3 deletions
@@ -90,6 +90,10 @@ static void uw_unwind_to_exit_point(void) /* Maintain consistency of unwind stack pointer */ uw_env_stack = uw_env_stack->ev.up_env; break; + case UW_GUARD: + format(std_error, lit("~a: cannot unwind across foreign stack frames\n"), + prog_string, nao); + abort(); default: break; } @@ -226,6 +230,14 @@ val uw_set_match_context(val context) return context; } +void uw_push_guard(uw_frame_t *fr) +{ + memset(fr, 0, sizeof *fr); + fr->uw.type = UW_GUARD; + fr->uw.up = uw_stack; + uw_stack = fr; +} + void uw_push_debug(uw_frame_t *fr, val func, struct args *args, val ub_p_a_pairs, val env, val data, val line, val chr) @@ -826,16 +838,31 @@ static val capture_cont(val tag, val fun, uw_frame_t *block) val uw_capture_cont(val tag, val fun, val ctx_form) { + uses_or2; uw_frame_t *fr; for (fr = uw_stack; fr != 0; fr = fr->uw.up) { - if ((fr->uw.type == UW_BLOCK || fr->uw.type == UW_CAPTURED_BLOCK) - && fr->bl.tag == tag) + switch (fr->uw.type) { + case UW_BLOCK: + case UW_CAPTURED_BLOCK: + if (fr->bl.tag != tag) + continue; break; + case UW_GUARD: + { + val sym = or2(car(default_bool_arg(ctx_form)), sys_capture_cont_s); + eval_error(ctx_form, lit("~s: cannot capture continuation " + "spanning external library stack frames"), + sym, nao); + } + default: + continue; + } + + break; } if (!fr) { - uses_or2; val sym = or2(car(default_bool_arg(ctx_form)), sys_capture_cont_s); if (tag) |