summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2021-01-21 01:02:48 -0800
committerKaz Kylheku <kaz@kylheku.com>2021-01-21 01:02:48 -0800
commit15cc57607711e8e3de2d97d67d04d72a8d08968b (patch)
tree509f7d6e9383355704a83265196349e633addff8
parent947b0979d05b190fee65698864cd1e14b5797f66 (diff)
downloadtxr-15cc57607711e8e3de2d97d67d04d72a8d08968b.tar.gz
txr-15cc57607711e8e3de2d97d67d04d72a8d08968b.tar.bz2
txr-15cc57607711e8e3de2d97d67d04d72a8d08968b.zip
iter-step: don't step through improper list terminators.
The issue is that iter-step will traverse (1 2 . 3) into the 3, and then that is valid iterator which continues via 4, 5, 6, ... This affects the each operator family which use iter-step. * lib.c (iter_step): Handle CONS and LCONS specially now. If the next object pulled via cdr is not a cons, and not nil, then throw an error. The default case now only possibly handles list-like sequences. Here we do something more generic and expensive: we enforce that the next iterator must be nil, or else a list-like sequence.
-rw-r--r--lib.c21
1 files changed, 20 insertions, 1 deletions
diff --git a/lib.c b/lib.c
index c35ef20f..9614a70d 100644
--- a/lib.c
+++ b/lib.c
@@ -1035,6 +1035,8 @@ val iter_item(val iter)
val iter_step(val iter)
{
+ val self = lit("iter-step");
+
switch (type(iter)) {
case NIL:
return nil;
@@ -1042,6 +1044,14 @@ val iter_step(val iter)
case NUM:
case BGNUM:
return plus(iter, one);
+ case CONS:
+ case LCONS:
+ {
+ val next = cdr(iter);
+ if (next && !consp(next))
+ uw_throwf(error_s, lit("~a: ~s is not a cons"), self, next, nao);
+ return next;
+ }
case COBJ:
if (iter->co.cls == seq_iter_s)
{
@@ -1057,7 +1067,16 @@ val iter_step(val iter)
}
/* fallthrough */
default:
- return cdr(iter);
+ {
+ val next = cdr(iter);
+ if (next) {
+ seq_info_t sinf = seq_info(next);
+ if (sinf.kind != SEQ_LISTLIKE)
+ uw_throwf(error_s, lit("~a: ~s is improperly terminated"),
+ self, iter, nao);
+ }
+ return next;
+ }
}
}