summaryrefslogtreecommitdiffstats
path: root/eval.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2019-08-31 22:10:26 -0700
committerKaz Kylheku <kaz@kylheku.com>2019-08-31 22:10:26 -0700
commit7dc1bd077837c61d2ebdeb53f7ae896a760011fe (patch)
tree5af29037377837cdfe5f107572b32065c1d48f6e /eval.c
parent7f433a9322af7d0cf4d0ded99a34113e82650add (diff)
downloadtxr-7dc1bd077837c61d2ebdeb53f7ae896a760011fe.tar.gz
txr-7dc1bd077837c61d2ebdeb53f7ae896a760011fe.tar.bz2
txr-7dc1bd077837c61d2ebdeb53f7ae896a760011fe.zip
interpreter: bug between let* and continuations.
This was discovered by user vapnik spaknik. If a let* form is evaluated in a top-level expression such that the incoming environment is null, and a continuation is captured in the init-form of the first variable, when that continuation is invoked, an exception is thrown: "copy-env: nil is not of type env". Short repro: 1> (block nil (let* ((x (yield 42))))) ** copy-env: nil is not of type env In fact, the bug isn't that we're trying to copy nil. the problem is we are trying to copy an environment we should not be copying at all. In fact, for sequential binding, there is no need for that logic at all; it's only parallel binding which needs it, because all of the init-forms are inserting bindings into the same environment. * eval.c (bindings_helper): Don't bother with registering a copy handler for sequential binding logic, because we don't mutate environments. All of that code is moved into the parallel case.
Diffstat (limited to 'eval.c')
-rw-r--r--eval.c25
1 files changed, 14 insertions, 11 deletions
diff --git a/eval.c b/eval.c
index eda2c857..ad8ed0c9 100644
--- a/eval.c
+++ b/eval.c
@@ -1654,12 +1654,7 @@ static val bindings_helper(val vars, val env, val sequential,
val ret_new_bindings, val ctx)
{
val iter, var;
- struct bindings_helper_vars v;
list_collect_decl (new_bindings, ptail);
- uw_frame_t uw_cc;
- v.ne = if3(sequential, env, make_env(nil, nil, env));
-
- uw_push_cont_copy(&uw_cc, coerce(mem_t *, &v), copy_bh_env_handler);
if (sequential) {
for (iter = vars; iter; iter = cdr(iter)) {
@@ -1668,22 +1663,30 @@ static val bindings_helper(val vars, val env, val sequential,
if (consp(item)) {
var = pop(&item);
- value = eval(pop(&item), v.ne, ctx);
+ value = eval(pop(&item), env, ctx);
} else {
var = item;
}
{
- val le = make_env(nil, nil, v.ne);
+ val le = make_env(nil, nil, env);
val binding = env_vbind(le, var, value);
if (ret_new_bindings)
ptail = list_collect (ptail, binding);
- v.ne = le;
+ env = le;
}
}
+
+ return env;
} else {
+ struct bindings_helper_vars v;
+ uw_frame_t uw_cc;
val de_in = dyn_env, new_de = de_in;
+ v.ne = make_env(nil, nil, env);
+
+ uw_push_cont_copy(&uw_cc, coerce(mem_t *, &v), copy_bh_env_handler);
+
for (iter = vars; iter; iter = cdr(iter)) {
val item = car(iter);
val value = nil;
@@ -1707,11 +1710,11 @@ static val bindings_helper(val vars, val env, val sequential,
}
}
dyn_env = new_de;
- }
- uw_pop_frame(&uw_cc);
+ uw_pop_frame(&uw_cc);
- return v.ne;
+ return v.ne;
+ }
}
static val fbindings_helper(val vars, val env, val lbind, val ctx)