diff options
| author | Paul Eggert | 2019-07-21 11:20:07 -0700 |
|---|---|---|
| committer | Paul Eggert | 2019-07-21 11:24:11 -0700 |
| commit | c72e6328b408805953a5adf832b5c5cc9f3a75e7 (patch) | |
| tree | 33e715f4a28ff12e9d6d5fa1b8cdc81d406a5838 | |
| parent | cf285946bee56912286f75e4d1215214bc7c5b4b (diff) | |
| download | emacs-c72e6328b408805953a5adf832b5c5cc9f3a75e7.tar.gz emacs-c72e6328b408805953a5adf832b5c5cc9f3a75e7.zip | |
Avoid integer overflow in hash table size
* src/fns.c (INDEX_SIZE_BOUND): Use a tighter bound.
(maybe_resize_hash_table): Avoid integer overflow when
checking for hash table size overflow. Fix confusion
between INDEX_SIZE_BOUND (which is for the index vector)
and hash table size. Fix typo in debugging message
when ENABLE_CHECKING.
| -rw-r--r-- | src/fns.c | 19 |
1 files changed, 13 insertions, 6 deletions
| @@ -4042,9 +4042,14 @@ allocate_hash_table (void) | |||
| 4042 | } | 4042 | } |
| 4043 | 4043 | ||
| 4044 | /* An upper bound on the size of a hash table index. It must fit in | 4044 | /* An upper bound on the size of a hash table index. It must fit in |
| 4045 | ptrdiff_t and be a valid Emacs fixnum. */ | 4045 | ptrdiff_t and be a valid Emacs fixnum. This is an upper bound on |
| 4046 | VECTOR_ELTS_MAX (see alloc.c) and gets as close as we can without | ||
| 4047 | violating modularity. */ | ||
| 4046 | #define INDEX_SIZE_BOUND \ | 4048 | #define INDEX_SIZE_BOUND \ |
| 4047 | ((ptrdiff_t) min (MOST_POSITIVE_FIXNUM, PTRDIFF_MAX / word_size)) | 4049 | ((ptrdiff_t) min (MOST_POSITIVE_FIXNUM, \ |
| 4050 | ((min (PTRDIFF_MAX, SIZE_MAX) \ | ||
| 4051 | - header_size - GCALIGNMENT) \ | ||
| 4052 | / word_size))) | ||
| 4048 | 4053 | ||
| 4049 | /* Create and initialize a new hash table. | 4054 | /* Create and initialize a new hash table. |
| 4050 | 4055 | ||
| @@ -4169,11 +4174,13 @@ maybe_resize_hash_table (struct Lisp_Hash_Table *h) | |||
| 4169 | else | 4174 | else |
| 4170 | { | 4175 | { |
| 4171 | double float_new_size = old_size * (rehash_size + 1); | 4176 | double float_new_size = old_size * (rehash_size + 1); |
| 4172 | if (float_new_size < INDEX_SIZE_BOUND + 1) | 4177 | if (float_new_size < EMACS_INT_MAX) |
| 4173 | new_size = float_new_size; | 4178 | new_size = float_new_size; |
| 4174 | else | 4179 | else |
| 4175 | new_size = INDEX_SIZE_BOUND + 1; | 4180 | new_size = EMACS_INT_MAX; |
| 4176 | } | 4181 | } |
| 4182 | if (PTRDIFF_MAX < new_size) | ||
| 4183 | new_size = PTRDIFF_MAX; | ||
| 4177 | if (new_size <= old_size) | 4184 | if (new_size <= old_size) |
| 4178 | new_size = old_size + 1; | 4185 | new_size = old_size + 1; |
| 4179 | 4186 | ||
| @@ -4181,7 +4188,7 @@ maybe_resize_hash_table (struct Lisp_Hash_Table *h) | |||
| 4181 | avoid problems if memory is exhausted. larger_vecalloc | 4188 | avoid problems if memory is exhausted. larger_vecalloc |
| 4182 | finishes computing the size of the replacement vectors. */ | 4189 | finishes computing the size of the replacement vectors. */ |
| 4183 | Lisp_Object next = larger_vecalloc (h->next, new_size - old_size, | 4190 | Lisp_Object next = larger_vecalloc (h->next, new_size - old_size, |
| 4184 | INDEX_SIZE_BOUND / 2); | 4191 | PTRDIFF_MAX / 2); |
| 4185 | ptrdiff_t next_size = ASIZE (next); | 4192 | ptrdiff_t next_size = ASIZE (next); |
| 4186 | for (ptrdiff_t i = old_size; i < next_size - 1; i++) | 4193 | for (ptrdiff_t i = old_size; i < next_size - 1; i++) |
| 4187 | gc_aset (next, i, make_fixnum (i + 1)); | 4194 | gc_aset (next, i, make_fixnum (i + 1)); |
| @@ -4216,7 +4223,7 @@ maybe_resize_hash_table (struct Lisp_Hash_Table *h) | |||
| 4216 | 4223 | ||
| 4217 | #ifdef ENABLE_CHECKING | 4224 | #ifdef ENABLE_CHECKING |
| 4218 | if (HASH_TABLE_P (Vpurify_flag) && XHASH_TABLE (Vpurify_flag) == h) | 4225 | if (HASH_TABLE_P (Vpurify_flag) && XHASH_TABLE (Vpurify_flag) == h) |
| 4219 | message ("Growing hash table to: %"pD"d", new_size); | 4226 | message ("Growing hash table to: %"pD"d", next_size); |
| 4220 | #endif | 4227 | #endif |
| 4221 | } | 4228 | } |
| 4222 | } | 4229 | } |