diff options
| author | Paul Eggert | 2011-06-14 15:32:12 -0700 |
|---|---|---|
| committer | Paul Eggert | 2011-06-14 15:32:12 -0700 |
| commit | e6966cd635f324edcc27adecb82cd85c71cbfcad (patch) | |
| tree | 0412f99ae48f617d75b9ae26b2f27eb7d018d592 /src | |
| parent | 00c604f263874880cc55a000af884c55743d6441 (diff) | |
| download | emacs-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/ChangeLog | 14 | ||||
| -rw-r--r-- | src/fns.c | 42 |
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 @@ | |||
| 1 | 2011-06-14 Paul Eggert <eggert@cs.ucla.edu> | 1 | 2011-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. |
| @@ -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. */ | ||
| 104 | enum { QUIT_COUNT_HEURISTIC = 1 << 16 }; | ||
| 105 | |||
| 102 | /* Random data-structure functions */ | 106 | /* Random data-structure functions */ |
| 103 | 107 | ||
| 104 | DEFUN ("length", Flength, Slength, 1, 1, 0, | 108 | DEFUN ("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 | |||
| 159 | which is at least the number of distinct elements. */) | 163 | which 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 | ||
| 180 | DEFUN ("string-bytes", Fstring_bytes, Sstring_bytes, 1, 1, 0, | 200 | DEFUN ("string-bytes", Fstring_bytes, Sstring_bytes, 1, 1, 0, |