From: Paul Eggert Date: Fri, 11 Jan 2019 05:35:31 +0000 (-0800) Subject: List lengths are always fixnums now X-Git-Tag: emacs-27.0.90~3834 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=470082de55f7b1c1cde8aabbb5b8de55b4b08f83;p=emacs.git 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. --- diff --git a/src/alloc.c b/src/alloc.c index 407ac725414..31e8da70161 100644 --- a/src/alloc.c +++ b/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); diff --git a/src/fns.c b/src/fns.c index 0fad6f47447..6fcb38e4b04 100644 --- a/src/fns.c +++ b/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); }