summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2016-08-28 09:50:44 -0700
committerKaz Kylheku <kaz@kylheku.com>2016-08-28 09:50:44 -0700
commit0b8eb423973d7e2ebb15c4a6b18befdfe6b23692 (patch)
tree86e1cb10c42e14fd968d5f7a2fb853a520f3c876
parentab98634ea8992722046ab857ec0eaec7cb024761 (diff)
downloadtxr-0b8eb423973d7e2ebb15c4a6b18befdfe6b23692.tar.gz
txr-0b8eb423973d7e2ebb15c4a6b18befdfe6b23692.tar.bz2
txr-0b8eb423973d7e2ebb15c4a6b18befdfe6b23692.zip
Fix runaway recursion in lazy struct initialization.
Staci-blowing test case: (defstruct foo nil bar) (mlet ((f (lnew foo bar (not f.bar)))) (prinl f.bar)) * struct.c (lazy_struct_init): Do not flip the lazy flag to zero here. The problem is that it's being done after the funcall(so->slot[0]), and so the struct is still marked for lazy initialization while that function is running. We could detect the circularity (as done in the force function) but that would create inflexibilities in lazy struct initialization. (check_init_lazy_struct): Flip the lazy flag to zero in this function before calling lazy_struct_init. * txr.1: Document behavior of struct being freely accessible during lazy initialization.
-rw-r--r--struct.c5
-rw-r--r--txr.16
2 files changed, 9 insertions, 2 deletions
diff --git a/struct.c b/struct.c
index 2075b42f..77e57c2e 100644
--- a/struct.c
+++ b/struct.c
@@ -436,7 +436,6 @@ static void lazy_struct_init(val sinst, struct struct_inst *si)
val cell = funcall(si->slot[0]);
cons_bind (plist, args, cell);
- si->lazy = 0;
si->slot[0] = nil;
if (args && !st->boactor) {
@@ -471,8 +470,10 @@ static void lazy_struct_init(val sinst, struct struct_inst *si)
INLINE void check_init_lazy_struct(val sinst, struct struct_inst *si)
{
- if (si->lazy)
+ if (si->lazy) {
+ si->lazy = 0;
lazy_struct_init(sinst, si);
+ }
}
val make_lazy_struct(val type, val argfun)
diff --git a/txr.1 b/txr.1
index 788ebb60..3a47d26e 100644
--- a/txr.1
+++ b/txr.1
@@ -20186,6 +20186,12 @@ arranged by
by a non-local exit such as an exception throw, the object's
finalizers, if any, are invoked.
+Lazy initialization does not detect cycles. Immediately prior to the lazy
+initialization of a struct, the struct is marked as no longer requiring
+initialization. Thus, during initialization, its instance slots may be
+freely accessed. Slots not yet initialized evaluate as
+.codn nil .
+
.coNP Macro @ with-slots
.synb
.mets (with-slots >> ({ slot | >> ( sym << slot )}*) < struct-expr