]> git.eshelyaron.com Git - emacs.git/commitdiff
List lengths are always fixnums now
authorPaul Eggert <eggert@cs.ucla.edu>
Fri, 11 Jan 2019 05:35:31 +0000 (21:35 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Fri, 11 Jan 2019 05:39:56 +0000 (21:39 -0800)
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.

src/alloc.c
src/fns.c

index 407ac725414dff31bb342ad1b7e829d37b4bab4e..31e8da70161fdd9a99aa88fb9d9f8fccb7a4b0e3 100644 (file)
@@ -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);
index 0fad6f47447a8bc9901be3a2b72422d007f3d4fb..6fcb38e4b04843bcd49618c9799faf301e51c8c4 100644 (file)
--- 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);
 }