aboutsummaryrefslogtreecommitdiffstats
path: root/src/alloc.c
diff options
context:
space:
mode:
authorPaul Eggert2024-07-20 15:52:05 -0700
committerPaul Eggert2024-07-20 16:16:22 -0700
commit515e5ad0de133f0a3d501bd6290ccc51d8462955 (patch)
tree620ff4a699eab76b3bcb441b5507b87854f00097 /src/alloc.c
parent76497a01425e19a6c3a02c1e3031061fa0e7885b (diff)
downloademacs-515e5ad0de133f0a3d501bd6290ccc51d8462955.tar.gz
emacs-515e5ad0de133f0a3d501bd6290ccc51d8462955.zip
Fix bool vector length overflow
* src/alloc.c (make_clear_bool_vector): It’s now the caller’s responsibility to make sure the bool vector length is in range. Add an eassert to double-check this. This lets some locals be ptrdiff_t not EMACS_INT. (Fmake_bool_vector, Fbool_vector): Check that bool vector lengths are in range. * src/lisp.h (BOOL_VECTOR_LENGTH_MAX): New macro. (bool_vector_words, bool_vector_bytes): Avoid undefined behavior if size == EMACS_INT_MAX - (BITS_PER_BITS_WORD - 1). This is mostly theoretical but it’s easy to do it right. * src/lread.c (read_bool_vector): Use EMACS_INT, not just ptrdiff_t. Check that length doesn’t exceed BOOL_VECTOR_LENGTH_MAX. This fixes an unlikely integer overflow where the calculated size went negative.
Diffstat (limited to 'src/alloc.c')
-rw-r--r--src/alloc.c16
1 files changed, 10 insertions, 6 deletions
diff --git a/src/alloc.c b/src/alloc.c
index 41679b52707..48b170b866f 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -2413,14 +2413,13 @@ bool_vector_fill (Lisp_Object a, Lisp_Object init)
2413Lisp_Object 2413Lisp_Object
2414make_clear_bool_vector (EMACS_INT nbits, bool clearit) 2414make_clear_bool_vector (EMACS_INT nbits, bool clearit)
2415{ 2415{
2416 eassert (0 <= nbits && nbits <= BOOL_VECTOR_LENGTH_MAX);
2416 Lisp_Object val; 2417 Lisp_Object val;
2417 EMACS_INT words = bool_vector_words (nbits); 2418 ptrdiff_t words = bool_vector_words (nbits);
2418 EMACS_INT word_bytes = words * sizeof (bits_word); 2419 ptrdiff_t word_bytes = words * sizeof (bits_word);
2419 EMACS_INT needed_elements = ((bool_header_size - header_size + word_bytes 2420 ptrdiff_t needed_elements = ((bool_header_size - header_size + word_bytes
2420 + word_size - 1) 2421 + word_size - 1)
2421 / word_size); 2422 / word_size);
2422 if (PTRDIFF_MAX < needed_elements)
2423 memory_full (SIZE_MAX);
2424 struct Lisp_Bool_Vector *p 2423 struct Lisp_Bool_Vector *p
2425 = (struct Lisp_Bool_Vector *) allocate_clear_vector (needed_elements, 2424 = (struct Lisp_Bool_Vector *) allocate_clear_vector (needed_elements,
2426 clearit); 2425 clearit);
@@ -2449,7 +2448,10 @@ LENGTH must be a number. INIT matters only in whether it is t or nil. */)
2449 (Lisp_Object length, Lisp_Object init) 2448 (Lisp_Object length, Lisp_Object init)
2450{ 2449{
2451 CHECK_FIXNAT (length); 2450 CHECK_FIXNAT (length);
2452 Lisp_Object val = make_clear_bool_vector (XFIXNAT (length), NILP (init)); 2451 EMACS_INT len = XFIXNAT (length);
2452 if (BOOL_VECTOR_LENGTH_MAX < len)
2453 memory_full (SIZE_MAX);
2454 Lisp_Object val = make_clear_bool_vector (len, NILP (init));
2453 return NILP (init) ? val : bool_vector_fill (val, init); 2455 return NILP (init) ? val : bool_vector_fill (val, init);
2454} 2456}
2455 2457
@@ -2459,6 +2461,8 @@ Allows any number of arguments, including zero.
2459usage: (bool-vector &rest OBJECTS) */) 2461usage: (bool-vector &rest OBJECTS) */)
2460 (ptrdiff_t nargs, Lisp_Object *args) 2462 (ptrdiff_t nargs, Lisp_Object *args)
2461{ 2463{
2464 if (BOOL_VECTOR_LENGTH_MAX < nargs)
2465 memory_full (SIZE_MAX);
2462 Lisp_Object vector = make_clear_bool_vector (nargs, true); 2466 Lisp_Object vector = make_clear_bool_vector (nargs, true);
2463 for (ptrdiff_t i = 0; i < nargs; i++) 2467 for (ptrdiff_t i = 0; i < nargs; i++)
2464 if (!NILP (args[i])) 2468 if (!NILP (args[i]))