From 15cc57607711e8e3de2d97d67d04d72a8d08968b Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Thu, 21 Jan 2021 01:02:48 -0800 Subject: 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. --- lib.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'lib.c') 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; + } } } -- cgit v1.2.3