diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2016-04-11 21:30:19 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2016-04-11 21:30:19 -0700 |
commit | 46a4099f9fedf89d1a8cc45cf566750ab7284863 (patch) | |
tree | 7b6d540d10c3e014d486e645fcb73a3bd65c9603 /glob.c | |
parent | 313f2a76069064fa2262e4aec5526a30c2fba047 (diff) | |
download | txr-46a4099f9fedf89d1a8cc45cf566750ab7284863.tar.gz txr-46a4099f9fedf89d1a8cc45cf566750ab7284863.tar.bz2 txr-46a4099f9fedf89d1a8cc45cf566750ab7284863.zip |
Harden glob: continuations, exceptions, re-entry.
* glob.c (s_exit_point): New static variable.
(errfunc_thunk): Set up a continuation guard frame, so
the error function cannot capture a continuation across
glob's stack frames. Intercept all unwinding with
a simple unwind block, save the exit point in the
global variable and then stop the unwinding by
setting the unwind frame's exit point to null.
(glob_wrap): Check for glob being re-entered and
throw error if so. If the glob callback bailed due
to unwinding (as seen by a non-null value in the
exit point global variable), clean up the glob memory
with globfree and continue the unwinding to the
exit point.
unwind.h (uw_curr_exit_point): New macro for accessing
saved exit point in pure unwind frame.
Diffstat (limited to 'glob.c')
-rw-r--r-- | glob.c | 36 |
1 files changed, 35 insertions, 1 deletions
@@ -27,19 +27,40 @@ #include <stdarg.h> #include <wchar.h> #include <signal.h> +#include <stdlib.h> #include <glob.h> #include "config.h" #include "lib.h" #include "gc.h" #include "utf8.h" #include "eval.h" +#include "signal.h" +#include "unwind.h" #include "glob.h" static val s_errfunc; +static uw_frame_t *s_exit_point; static int errfunc_thunk(const char *errpath, int errcode) { - val result = funcall2(s_errfunc, string_utf8(errpath), num(errcode)); + val result = t; + uw_frame_t cont_guard; + + uw_push_guard(&cont_guard); + + uw_simple_catch_begin; + + result = funcall2(s_errfunc, string_utf8(errpath), num(errcode)); + + uw_unwind { + s_exit_point = uw_curr_exit_point; + uw_curr_exit_point = 0; /* stops unwinding */ + } + + uw_catch_end; + + uw_pop_frame(&cont_guard); + return result ? 1 : 0; } @@ -48,11 +69,24 @@ val glob_wrap(val pattern, val flags, val errfunc) char *pat_u8 = utf8_dup_to(c_str(pattern)); glob_t gl; + if (s_errfunc) + uw_throwf(error_s, lit("glob: glob cannot be re-entered from " + "its error callback function"), nao); + s_errfunc = default_bool_arg(errfunc); (void) glob(pat_u8, c_num(default_arg(flags, zero)), s_errfunc ? errfunc_thunk : 0, &gl); + s_errfunc = nil; + + if (s_exit_point) { + uw_frame_t *ep = s_exit_point; + s_exit_point = 0; + globfree(&gl); + uw_continue(ep); + } + { size_t i; list_collect_decl (out, ptail); |