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.
This commit is contained in:
parent
cb78b43f39
commit
79b9f05d3a
3 changed files with 30 additions and 23 deletions
44
src/alloc.c
44
src/alloc.c
|
@ -453,6 +453,7 @@ no_sanitize_memcpy (void *dest, void const *src, size_t size)
|
|||
|
||||
#endif /* MAX_SAVE_STACK > 0 */
|
||||
|
||||
static struct Lisp_Vector *allocate_clear_vector (ptrdiff_t, bool);
|
||||
static void unchain_finalizer (struct Lisp_Finalizer *);
|
||||
static void mark_terminals (void);
|
||||
static void gc_sweep (void);
|
||||
|
@ -2406,10 +2407,11 @@ bool_vector_fill (Lisp_Object a, Lisp_Object init)
|
|||
return a;
|
||||
}
|
||||
|
||||
/* Return a newly allocated, uninitialized bool vector of size NBITS. */
|
||||
/* Return a newly allocated, bool vector of size NBITS. If CLEARIT,
|
||||
clear its slots; otherwise the vector's slots are uninitialized. */
|
||||
|
||||
Lisp_Object
|
||||
make_uninit_bool_vector (EMACS_INT nbits)
|
||||
make_clear_bool_vector (EMACS_INT nbits, bool clearit)
|
||||
{
|
||||
Lisp_Object val;
|
||||
EMACS_INT words = bool_vector_words (nbits);
|
||||
|
@ -2420,28 +2422,35 @@ make_uninit_bool_vector (EMACS_INT nbits)
|
|||
if (PTRDIFF_MAX < needed_elements)
|
||||
memory_full (SIZE_MAX);
|
||||
struct Lisp_Bool_Vector *p
|
||||
= (struct Lisp_Bool_Vector *) allocate_vector (needed_elements);
|
||||
= (struct Lisp_Bool_Vector *) allocate_clear_vector (needed_elements,
|
||||
clearit);
|
||||
/* Clear padding at end; but only if necessary, to avoid polluting the
|
||||
data cache. */
|
||||
if (!clearit && nbits % BITS_PER_BITS_WORD != 0)
|
||||
p->data[words - 1] = 0;
|
||||
|
||||
XSETVECTOR (val, p);
|
||||
XSETPVECTYPESIZE (XVECTOR (val), PVEC_BOOL_VECTOR, 0, 0);
|
||||
p->size = nbits;
|
||||
|
||||
/* Clear padding at the end. */
|
||||
if (words)
|
||||
p->data[words - 1] = 0;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Return a newly allocated, uninitialized bool vector of size NBITS. */
|
||||
|
||||
Lisp_Object
|
||||
make_uninit_bool_vector (EMACS_INT nbits)
|
||||
{
|
||||
return make_clear_bool_vector (nbits, false);
|
||||
}
|
||||
|
||||
DEFUN ("make-bool-vector", Fmake_bool_vector, Smake_bool_vector, 2, 2, 0,
|
||||
doc: /* Return a new bool-vector of length LENGTH, using INIT for each element.
|
||||
LENGTH must be a number. INIT matters only in whether it is t or nil. */)
|
||||
(Lisp_Object length, Lisp_Object init)
|
||||
{
|
||||
Lisp_Object val;
|
||||
|
||||
CHECK_FIXNAT (length);
|
||||
val = make_uninit_bool_vector (XFIXNAT (length));
|
||||
return bool_vector_fill (val, init);
|
||||
Lisp_Object val = make_clear_bool_vector (XFIXNAT (length), NILP (init));
|
||||
return NILP (init) ? val : bool_vector_fill (val, init);
|
||||
}
|
||||
|
||||
DEFUN ("bool-vector", Fbool_vector, Sbool_vector, 0, MANY, 0,
|
||||
|
@ -2450,13 +2459,10 @@ Allows any number of arguments, including zero.
|
|||
usage: (bool-vector &rest OBJECTS) */)
|
||||
(ptrdiff_t nargs, Lisp_Object *args)
|
||||
{
|
||||
ptrdiff_t i;
|
||||
Lisp_Object vector;
|
||||
|
||||
vector = make_uninit_bool_vector (nargs);
|
||||
for (i = 0; i < nargs; i++)
|
||||
bool_vector_set (vector, i, !NILP (args[i]));
|
||||
|
||||
Lisp_Object vector = make_clear_bool_vector (nargs, true);
|
||||
for (ptrdiff_t i = 0; i < nargs; i++)
|
||||
if (!NILP (args[i]))
|
||||
bool_vector_set (vector, i, true);
|
||||
return vector;
|
||||
}
|
||||
|
||||
|
|
|
@ -2309,12 +2309,12 @@ See also the function `nreverse', which is used more often. */)
|
|||
}
|
||||
else if (BOOL_VECTOR_P (seq))
|
||||
{
|
||||
ptrdiff_t i;
|
||||
EMACS_INT nbits = bool_vector_size (seq);
|
||||
|
||||
new = make_uninit_bool_vector (nbits);
|
||||
for (i = 0; i < nbits; i++)
|
||||
bool_vector_set (new, i, bool_vector_bitref (seq, nbits - i - 1));
|
||||
new = make_clear_bool_vector (nbits, true);
|
||||
for (ptrdiff_t i = 0; i < nbits; i++)
|
||||
if (bool_vector_bitref (seq, nbits - i - 1))
|
||||
bool_vector_set (new, i, true);
|
||||
}
|
||||
else if (STRINGP (seq))
|
||||
{
|
||||
|
|
|
@ -4578,6 +4578,7 @@ list4i (intmax_t a, intmax_t b, intmax_t c, intmax_t d)
|
|||
return list4 (make_int (a), make_int (b), make_int (c), make_int (d));
|
||||
}
|
||||
|
||||
extern Lisp_Object make_clear_bool_vector (EMACS_INT, bool);
|
||||
extern Lisp_Object make_uninit_bool_vector (EMACS_INT);
|
||||
extern Lisp_Object bool_vector_fill (Lisp_Object, Lisp_Object);
|
||||
extern AVOID string_overflow (void);
|
||||
|
|
Loading…
Add table
Reference in a new issue