List lengths are always fixnums now
Without this patch, it was theoretically possible for a list length to be a bignum, which means that safe-length could signal an error (due to generating a too-large bignum) contrary to its documentation. Fix things to remove the theoretical possibility, so that list lengths are always fixnums (and so that list lenghts are always ptrdiff_t values too, since that is assumed internally anyway). * src/alloc.c (Fcons): Do not allocate so many conses that a list length won’t fit into ptrdiff_t or into fixnum. This matters only on weird platforms; on typical platforms, list lengths always fit anyway. * src/fns.c (list_length, Fsafe_length, proper-list-p): Remove integer overflow checks that are no longer needed.
This commit is contained in:
parent
9609db9d98
commit
470082de55
2 changed files with 16 additions and 8 deletions
13
src/alloc.c
13
src/alloc.c
|
@ -2774,6 +2774,19 @@ DEFUN ("cons", Fcons, Scons, 2, 2, 0,
|
|||
{
|
||||
if (cons_block_index == CONS_BLOCK_SIZE)
|
||||
{
|
||||
/* Maximum number of conses that should be active at any
|
||||
given time, so that list lengths fit into a ptrdiff_t and
|
||||
into a fixnum. */
|
||||
ptrdiff_t max_conses = min (PTRDIFF_MAX, MOST_POSITIVE_FIXNUM);
|
||||
|
||||
/* This check is typically optimized away, as a runtime
|
||||
check is needed only on weird platforms where a count of
|
||||
distinct conses might not fit. */
|
||||
if (max_conses < INTPTR_MAX / sizeof (struct Lisp_Cons)
|
||||
&& (max_conses - CONS_BLOCK_SIZE
|
||||
< total_free_conses + total_conses))
|
||||
memory_full (sizeof (struct cons_block));
|
||||
|
||||
struct cons_block *new
|
||||
= lisp_align_malloc (sizeof *new, MEM_TYPE_CONS);
|
||||
memset (new->gcmarkbits, 0, sizeof new->gcmarkbits);
|
||||
|
|
11
src/fns.c
11
src/fns.c
|
@ -101,9 +101,7 @@ list_length (Lisp_Object list)
|
|||
FOR_EACH_TAIL (list)
|
||||
i++;
|
||||
CHECK_LIST_END (list, list);
|
||||
if (i <= min (PTRDIFF_MAX, MOST_POSITIVE_FIXNUM))
|
||||
return i;
|
||||
overflow_error ();
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
|
@ -141,14 +139,13 @@ DEFUN ("safe-length", Fsafe_length, Ssafe_length, 1, 1, 0,
|
|||
doc: /* Return the length of a list, but avoid error or infinite loop.
|
||||
This function never gets an error. If LIST is not really a list,
|
||||
it returns 0. If LIST is circular, it returns an integer that is at
|
||||
least the number of distinct elements.
|
||||
Value is a fixnum, if it's small enough, otherwise a bignum. */)
|
||||
least the number of distinct elements. */)
|
||||
(Lisp_Object list)
|
||||
{
|
||||
intptr_t len = 0;
|
||||
FOR_EACH_TAIL_SAFE (list)
|
||||
len++;
|
||||
return INT_TO_INTEGER (len);
|
||||
return make_fixnum (len);
|
||||
}
|
||||
|
||||
DEFUN ("proper-list-p", Fproper_list_p, Sproper_list_p, 1, 1, 0,
|
||||
|
@ -168,8 +165,6 @@ A proper list is neither circular nor dotted (i.e., its last cdr is nil). */
|
|||
}
|
||||
if (!NILP (last_tail))
|
||||
return Qnil;
|
||||
if (MOST_POSITIVE_FIXNUM < len)
|
||||
overflow_error ();
|
||||
return make_fixnum (len);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue