summaryrefslogtreecommitdiffstats
path: root/struct.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2015-10-10 23:22:42 -0700
committerKaz Kylheku <kaz@kylheku.com>2015-10-10 23:22:42 -0700
commitec3ef435c68af026ddfca6fa312bde18077194b8 (patch)
tree74d73dedc3fdf652b3409e880d490b9fe475a36a /struct.c
parent46a525574121efd4e2ad5d1420d2ba11a67e9a1c (diff)
downloadtxr-ec3ef435c68af026ddfca6fa312bde18077194b8.tar.gz
txr-ec3ef435c68af026ddfca6fa312bde18077194b8.tar.bz2
txr-ec3ef435c68af026ddfca6fa312bde18077194b8.zip
Invoke finalizers if object initialization bails.
* struct.c (make_struct): Add unwind protection around the initialization of the struct object, which calls the partially initialized object's finalizers if initialization is abandoned by a non-local exit. * txr.1: Document the behavior, under make-struct and the new macro.
Diffstat (limited to 'struct.c')
-rw-r--r--struct.c12
1 files changed, 12 insertions, 0 deletions
diff --git a/struct.c b/struct.c
index 7162dc3e..7b8c2f72 100644
--- a/struct.c
+++ b/struct.c
@@ -339,6 +339,7 @@ val make_struct(val type, val plist, struct args *args)
size_t size = offsetof(struct struct_inst, slot) + sizeof (val) * nslots;
struct struct_inst *si = coerce(struct struct_inst *, chk_malloc(size));
val sinst;
+ volatile val inited = nil;
if (args_more(args, 0) && !st->boactor) {
free(si);
@@ -357,6 +358,8 @@ val make_struct(val type, val plist, struct args *args)
si->type = type;
+ uw_simple_catch_begin;
+
call_initfun_chain(st, sinst);
for (; plist; plist = cddr(plist))
@@ -369,6 +372,15 @@ val make_struct(val type, val plist, struct args *args)
generic_funcall(st->boactor, args_copy);
}
+ inited = t;
+
+ uw_unwind {
+ if (!inited)
+ gc_call_finalizers(sinst);
+ }
+
+ uw_catch_end;
+
return sinst;
}
}