aboutsummaryrefslogtreecommitdiffstats
path: root/src/alloc.c
diff options
context:
space:
mode:
authorPaul Eggert2024-07-20 00:17:14 -0700
committerPaul Eggert2024-07-20 00:19:33 -0700
commit79b9f05d3a44b25db9fd3eff9cc002324cfa790c (patch)
tree0aad9dcb93934de2496293ce8d87c8a1c7ca1a12 /src/alloc.c
parentcb78b43f39432af3301a39507eac23f5f1e9fbf3 (diff)
downloademacs-79b9f05d3a44b25db9fd3eff9cc002324cfa790c.tar.gz
emacs-79b9f05d3a44b25db9fd3eff9cc002324cfa790c.zip
Avoid accessing uninitialized bool_vector words
Although loading uninitialized works from memory and then ignoring the result works fine on conventional architectures, it technically has undefined behavior in C, so redo bool_vector allocation so that the code never does that. This can improve performance when allocating large vectors of nil, since calloc can clear the memory lazily. * src/alloc.c (make_clear_bool_vector): New function, a generalization of make_uninit_bool_vector. (make_uninit_bool_vector): Use it. (Fmake_bool_vector): If !INIT, rely on make_clear_bool_vector. * src/alloc.c (Fbool_vector): * src/fns.c (Freverse): Don’t access uninitialized bool_vector words.
Diffstat (limited to 'src/alloc.c')
-rw-r--r--src/alloc.c42
1 files changed, 24 insertions, 18 deletions
diff --git a/src/alloc.c b/src/alloc.c
index 52f8a65d59d..41679b52707 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -453,6 +453,7 @@ no_sanitize_memcpy (void *dest, void const *src, size_t size)
453 453
454#endif /* MAX_SAVE_STACK > 0 */ 454#endif /* MAX_SAVE_STACK > 0 */
455 455
456static struct Lisp_Vector *allocate_clear_vector (ptrdiff_t, bool);
456static void unchain_finalizer (struct Lisp_Finalizer *); 457static void unchain_finalizer (struct Lisp_Finalizer *);
457static void mark_terminals (void); 458static void mark_terminals (void);
458static void gc_sweep (void); 459static void gc_sweep (void);
@@ -2406,10 +2407,11 @@ bool_vector_fill (Lisp_Object a, Lisp_Object init)
2406 return a; 2407 return a;
2407} 2408}
2408 2409
2409/* Return a newly allocated, uninitialized bool vector of size NBITS. */ 2410/* Return a newly allocated, bool vector of size NBITS. If CLEARIT,
2411 clear its slots; otherwise the vector's slots are uninitialized. */
2410 2412
2411Lisp_Object 2413Lisp_Object
2412make_uninit_bool_vector (EMACS_INT nbits) 2414make_clear_bool_vector (EMACS_INT nbits, bool clearit)
2413{ 2415{
2414 Lisp_Object val; 2416 Lisp_Object val;
2415 EMACS_INT words = bool_vector_words (nbits); 2417 EMACS_INT words = bool_vector_words (nbits);
@@ -2420,16 +2422,25 @@ make_uninit_bool_vector (EMACS_INT nbits)
2420 if (PTRDIFF_MAX < needed_elements) 2422 if (PTRDIFF_MAX < needed_elements)
2421 memory_full (SIZE_MAX); 2423 memory_full (SIZE_MAX);
2422 struct Lisp_Bool_Vector *p 2424 struct Lisp_Bool_Vector *p
2423 = (struct Lisp_Bool_Vector *) allocate_vector (needed_elements); 2425 = (struct Lisp_Bool_Vector *) allocate_clear_vector (needed_elements,
2426 clearit);
2427 /* Clear padding at end; but only if necessary, to avoid polluting the
2428 data cache. */
2429 if (!clearit && nbits % BITS_PER_BITS_WORD != 0)
2430 p->data[words - 1] = 0;
2431
2424 XSETVECTOR (val, p); 2432 XSETVECTOR (val, p);
2425 XSETPVECTYPESIZE (XVECTOR (val), PVEC_BOOL_VECTOR, 0, 0); 2433 XSETPVECTYPESIZE (XVECTOR (val), PVEC_BOOL_VECTOR, 0, 0);
2426 p->size = nbits; 2434 p->size = nbits;
2435 return val;
2436}
2427 2437
2428 /* Clear padding at the end. */ 2438/* Return a newly allocated, uninitialized bool vector of size NBITS. */
2429 if (words)
2430 p->data[words - 1] = 0;
2431 2439
2432 return val; 2440Lisp_Object
2441make_uninit_bool_vector (EMACS_INT nbits)
2442{
2443 return make_clear_bool_vector (nbits, false);
2433} 2444}
2434 2445
2435DEFUN ("make-bool-vector", Fmake_bool_vector, Smake_bool_vector, 2, 2, 0, 2446DEFUN ("make-bool-vector", Fmake_bool_vector, Smake_bool_vector, 2, 2, 0,
@@ -2437,11 +2448,9 @@ DEFUN ("make-bool-vector", Fmake_bool_vector, Smake_bool_vector, 2, 2, 0,
2437LENGTH must be a number. INIT matters only in whether it is t or nil. */) 2448LENGTH must be a number. INIT matters only in whether it is t or nil. */)
2438 (Lisp_Object length, Lisp_Object init) 2449 (Lisp_Object length, Lisp_Object init)
2439{ 2450{
2440 Lisp_Object val;
2441
2442 CHECK_FIXNAT (length); 2451 CHECK_FIXNAT (length);
2443 val = make_uninit_bool_vector (XFIXNAT (length)); 2452 Lisp_Object val = make_clear_bool_vector (XFIXNAT (length), NILP (init));
2444 return bool_vector_fill (val, init); 2453 return NILP (init) ? val : bool_vector_fill (val, init);
2445} 2454}
2446 2455
2447DEFUN ("bool-vector", Fbool_vector, Sbool_vector, 0, MANY, 0, 2456DEFUN ("bool-vector", Fbool_vector, Sbool_vector, 0, MANY, 0,
@@ -2450,13 +2459,10 @@ Allows any number of arguments, including zero.
2450usage: (bool-vector &rest OBJECTS) */) 2459usage: (bool-vector &rest OBJECTS) */)
2451 (ptrdiff_t nargs, Lisp_Object *args) 2460 (ptrdiff_t nargs, Lisp_Object *args)
2452{ 2461{
2453 ptrdiff_t i; 2462 Lisp_Object vector = make_clear_bool_vector (nargs, true);
2454 Lisp_Object vector; 2463 for (ptrdiff_t i = 0; i < nargs; i++)
2455 2464 if (!NILP (args[i]))
2456 vector = make_uninit_bool_vector (nargs); 2465 bool_vector_set (vector, i, true);
2457 for (i = 0; i < nargs; i++)
2458 bool_vector_set (vector, i, !NILP (args[i]));
2459
2460 return vector; 2466 return vector;
2461} 2467}
2462 2468