diff options
| author | Paul Eggert | 2024-07-20 00:17:14 -0700 |
|---|---|---|
| committer | Paul Eggert | 2024-07-20 00:19:33 -0700 |
| commit | 79b9f05d3a44b25db9fd3eff9cc002324cfa790c (patch) | |
| tree | 0aad9dcb93934de2496293ce8d87c8a1c7ca1a12 /src/alloc.c | |
| parent | cb78b43f39432af3301a39507eac23f5f1e9fbf3 (diff) | |
| download | emacs-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.c | 42 |
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 | ||
| 456 | static struct Lisp_Vector *allocate_clear_vector (ptrdiff_t, bool); | ||
| 456 | static void unchain_finalizer (struct Lisp_Finalizer *); | 457 | static void unchain_finalizer (struct Lisp_Finalizer *); |
| 457 | static void mark_terminals (void); | 458 | static void mark_terminals (void); |
| 458 | static void gc_sweep (void); | 459 | static 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 | ||
| 2411 | Lisp_Object | 2413 | Lisp_Object |
| 2412 | make_uninit_bool_vector (EMACS_INT nbits) | 2414 | make_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; | 2440 | Lisp_Object |
| 2441 | make_uninit_bool_vector (EMACS_INT nbits) | ||
| 2442 | { | ||
| 2443 | return make_clear_bool_vector (nbits, false); | ||
| 2433 | } | 2444 | } |
| 2434 | 2445 | ||
| 2435 | DEFUN ("make-bool-vector", Fmake_bool_vector, Smake_bool_vector, 2, 2, 0, | 2446 | DEFUN ("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, | |||
| 2437 | LENGTH must be a number. INIT matters only in whether it is t or nil. */) | 2448 | LENGTH 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 | ||
| 2447 | DEFUN ("bool-vector", Fbool_vector, Sbool_vector, 0, MANY, 0, | 2456 | DEFUN ("bool-vector", Fbool_vector, Sbool_vector, 0, MANY, 0, |
| @@ -2450,13 +2459,10 @@ Allows any number of arguments, including zero. | |||
| 2450 | usage: (bool-vector &rest OBJECTS) */) | 2459 | usage: (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 | ||