>>>> "Kyle" == Kyle Jones
<kyle_jones(a)wonderworks.com> writes:
Kyle> Jan Vroonhof writes:
> Here is an easier one
>
> (let ((lijst '(a b c)))
> (mapcar
> (lambda (x)
> ;; Make list shorter behind mapcar's back
> (delete 'c lijst))
> lijst))
>
> The problem is this code in in mapcar1
>
> if (LISTP (seq))
> {
> for (i = 0; i < leni; i++)
> {
> args[1] = XCAR (seq);
> seq = XCDR (seq);
> result = Ffuncall (2, args);
> if (vals) vals[gcpro1.nvars++] = result;
> }
> }
>
> It blindingly believes that XCDR(seq) will always be a cons cell,
> although it calls user code which could have modified the list it is
> iterating over.
Kyle> Here's a patch that fixes this. Recommended for 21.1 and 21.2.
There's another GC bug with this code I tried to fix. If you are
iterating over the list, and the mapping function destructively
modifies the list by breaking it in the middle using (setcdr), the
remaining list will not have any references and can be garbage
collected.
If you evaluate this in a debug xemacs, it will crash.
(let ((x (list (cons 1 1) (cons 2 2) (cons 3 3) (cons 4 4))))
(mapcar (lambda (y)
(garbage-collect)
(when (eq (car y) 2)
(setcdr x nil)
(garbage-collect))
(print (car y)))
x))
However, my own patch needs more work as well, I think. Perhaps I
should separate out the dostring fiddling from the pure bug fix, eh?
So, for the time being I veto both of our patches. I want to finish
this work since I feel vaguely responsible for the core lisp stuff.
Kyle> 1999-12-16 Kyle Jones <kyle_jones(a)wonderworks.com>
Kyle> * fns.c (mapcar1): when iterating over a list, check for
Kyle> CONSP each iteration because bad user code might have
Kyle> modified the list. Call Fcdr/Fcar if CONSP check fails
Kyle> so that malformed lists cause an error to be signaled
Kyle> instead of crashing.
Kyle> --- src/fns.c 1999/10/24 03:48:39 1.30.2.23
Kyle> +++ src/fns.c 1999/12/17 04:13:14
Kyle> @@ -3070,8 +3070,19 @@
Kyle> {
Kyle> for (i = 0; i < leni; i++)
Kyle> {
Kyle> - args[1] = XCAR (seq);
Kyle> - seq = XCDR (seq);
Kyle> + /* Use XCAR/XCDR to avoid function call overhead if we can.
Kyle> + Otherwise call Fcar and Fcdr to get exceptions signaled
Kyle> + if the Lisp code mangles the list. */
Kyle> + if (CONSP (seq))
Kyle> + {
Kyle> + args[1] = XCAR (seq);
Kyle> + seq = XCDR (seq);
Kyle> + }
Kyle> + else
Kyle> + {
Kyle> + args[1] = Fcar (seq);
Kyle> + seq = Fcdr (seq);
Kyle> + }
Kyle> result = Ffuncall (2, args);
Kyle> if (vals) vals[gcpro1.nvars++] = result;
Kyle> }