aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2011-06-14 15:32:12 -0700
committerPaul Eggert2011-06-14 15:32:12 -0700
commite6966cd635f324edcc27adecb82cd85c71cbfcad (patch)
tree0412f99ae48f617d75b9ae26b2f27eb7d018d592 /src
parent00c604f263874880cc55a000af884c55743d6441 (diff)
downloademacs-e6966cd635f324edcc27adecb82cd85c71cbfcad.tar.gz
emacs-e6966cd635f324edcc27adecb82cd85c71cbfcad.zip
* fns.c: Don't overflow int when computing a list length.
(Fsafe_length): Return a float if the value is not representable as a fixnum. This shouldn't happen except in contrived situations. Use same QUIT_COUNT_HEURISTIC as Flength now does.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog14
-rw-r--r--src/fns.c42
2 files changed, 40 insertions, 16 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 5d70c56cc5c..3c690a5cae0 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,10 +1,14 @@
12011-06-14 Paul Eggert <eggert@cs.ucla.edu> 12011-06-14 Paul Eggert <eggert@cs.ucla.edu>
2 2
3 * fns.c (Flength): Don't overflow int when computing a list length. 3 * fns.c: Don't overflow int when computing a list length.
4 Use EMACS_INT, not int, to avoid unwanted truncation on 64-bit hosts. 4 * fns.c (QUIT_COUNT_HEURISTIC): New constant.
5 Check for QUIT every 1024 entries rather than every other entry; 5 (Flength, Fsafe_length): Use EMACS_INT, not int, to avoid unwanted
6 that's faster and is responsive enough. Report an error instead of 6 truncation on 64-bit hosts. Check for QUIT every
7 overflowing an integer. 7 QUIT_COUNT_HEURISTIC entries rather than every other entry; that's
8 faster and is responsive enough.
9 (Flength): Report an error instead of overflowing an integer.
10 (Fsafe_length): Return a float if the value is not representable
11 as a fixnum. This shouldn't happen except in contrived situations.
8 12
9 * alloc.c: Check that resized vectors' lengths fit in fixnums. 13 * alloc.c: Check that resized vectors' lengths fit in fixnums.
10 (header_size, word_size): New constants. 14 (header_size, word_size): New constants.
diff --git a/src/fns.c b/src/fns.c
index 7d5d1bd5d99..10af162cfc4 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -99,6 +99,10 @@ Other values of LIMIT are ignored. */)
99 return lispy_val; 99 return lispy_val;
100} 100}
101 101
102/* Heuristic on how many iterations of a tight loop can be safely done
103 before it's time to do a QUIT. This must be a power of 2. */
104enum { QUIT_COUNT_HEURISTIC = 1 << 16 };
105
102/* Random data-structure functions */ 106/* Random data-structure functions */
103 107
104DEFUN ("length", Flength, Slength, 1, 1, 0, 108DEFUN ("length", Flength, Slength, 1, 1, 0,
@@ -128,7 +132,7 @@ To get the number of bytes, use `string-bytes'. */)
128 do 132 do
129 { 133 {
130 ++i; 134 ++i;
131 if ((i & ((1 << 10) - 1)) == 0) 135 if ((i & (QUIT_COUNT_HEURISTIC - 1)) == 0)
132 { 136 {
133 if (MOST_POSITIVE_FIXNUM < i) 137 if (MOST_POSITIVE_FIXNUM < i)
134 error ("List too long"); 138 error ("List too long");
@@ -159,22 +163,38 @@ it returns 0. If LIST is circular, it returns a finite value
159which is at least the number of distinct elements. */) 163which is at least the number of distinct elements. */)
160 (Lisp_Object list) 164 (Lisp_Object list)
161{ 165{
162 Lisp_Object tail, halftail, length; 166 Lisp_Object tail, halftail;
163 int len = 0; 167 double hilen = 0;
168 uintmax_t lolen = 1;
169
170 if (! CONSP (list))
171 return 0;
164 172
165 /* halftail is used to detect circular lists. */ 173 /* halftail is used to detect circular lists. */
166 halftail = list; 174 for (tail = halftail = list; ; )
167 for (tail = list; CONSP (tail); tail = XCDR (tail))
168 { 175 {
169 if (EQ (tail, halftail) && len != 0) 176 tail = XCDR (tail);
177 if (! CONSP (tail))
170 break; 178 break;
171 len++; 179 if (EQ (tail, halftail))
172 if ((len & 1) == 0) 180 break;
173 halftail = XCDR (halftail); 181 lolen++;
182 if ((lolen & 1) == 0)
183 {
184 halftail = XCDR (halftail);
185 if ((lolen & (QUIT_COUNT_HEURISTIC - 1)) == 0)
186 {
187 QUIT;
188 if (lolen == 0)
189 hilen += UINTMAX_MAX + 1.0;
190 }
191 }
174 } 192 }
175 193
176 XSETINT (length, len); 194 /* If the length does not fit into a fixnum, return a float.
177 return length; 195 On all known practical machines this returns an upper bound on
196 the true length. */
197 return hilen ? make_float (hilen + lolen) : make_fixnum_or_float (lolen);
178} 198}
179 199
180DEFUN ("string-bytes", Fstring_bytes, Sstring_bytes, 1, 1, 0, 200DEFUN ("string-bytes", Fstring_bytes, Sstring_bytes, 1, 1, 0,