summaryrefslogtreecommitdiffstats
path: root/glob.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2016-04-11 21:30:19 -0700
committerKaz Kylheku <kaz@kylheku.com>2016-04-11 21:30:19 -0700
commit46a4099f9fedf89d1a8cc45cf566750ab7284863 (patch)
tree7b6d540d10c3e014d486e645fcb73a3bd65c9603 /glob.c
parent313f2a76069064fa2262e4aec5526a30c2fba047 (diff)
downloadtxr-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.c36
1 files changed, 35 insertions, 1 deletions
diff --git a/glob.c b/glob.c
index dcab2ed8..76673a59 100644
--- a/glob.c
+++ b/glob.c
@@ -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);