diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2019-08-31 22:10:26 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2019-08-31 22:10:26 -0700 |
commit | 7dc1bd077837c61d2ebdeb53f7ae896a760011fe (patch) | |
tree | 5af29037377837cdfe5f107572b32065c1d48f6e /eval.c | |
parent | 7f433a9322af7d0cf4d0ded99a34113e82650add (diff) | |
download | txr-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.c | 25 |
1 files changed, 14 insertions, 11 deletions
@@ -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) |