Pacify GCC -Wanalyzer-possible-null-dereference

This fixes the only remaining GCC diagnostics when emacs-28 is
configured with --enable-gcc-warnings.  It does so by adding
ATTRIBUTE_RETURNS_NONNULL so that GCC knows certain functions
return nonnull.  It also arranges for three of those functions to
always return nonnull; I thought these functions already were
doing so, but apparently not, and it is conceivable (though I
haven’t checked this) that changing these functions to always
return nonnull even on non-GNU platforms may fix unlikely
portability bugs elsewhere in Emacs.  I used GCC 11.2.1 20210728
(Red Hat 11.2.1-1) on x86-64 when checking the diagnostics.
* configure.ac: Invoke gl_EEMALLOC before gl_INIT, in case
the regex code doesn't invoke gl_EEMALLOC; needed for src/alloc.c’s
use of MALLOC_0_IS_NONNULL.
* src/alloc.c (xmalloc, xzalloc, xrealloc): Don’t worry about the
special case where SIZE == 0, since lmalloc and lrealloc now
return null only on allocation failure.
(lmalloc, lrealloc): Return null only on allocation failure,
instead of having special cases that treat malloc (0) and
realloc (X, 0) as successes even when they return null.
* src/lisp.h: Add ATTRIBUTE_RETURNS_NONNULL to a few functions
that always return nonnull pointers, so that gcc -fanalyzer
does not issue diagnostics like “alloc.c: In function
‘allocate_vector_block’: alloc.c:2985:15: warning: dereference of
possibly-NULL ‘block’ [CWE-690] [-Wanalyzer-possible-null-dereference]”
as per <https://cwe.mitre.org/data/definitions/690.html>.
This commit is contained in:
Paul Eggert 2021-10-13 11:16:33 -07:00
parent 8e072e6abe
commit 33525102e7
3 changed files with 56 additions and 34 deletions

View file

@ -5673,6 +5673,7 @@ CFLAGS=$pre_PKG_CONFIG_CFLAGS
LIBS="$LIB_PTHREAD $pre_PKG_CONFIG_LIBS"
gl_ASSERT_NO_GNULIB_POSIXCHECK
gl_ASSERT_NO_GNULIB_TESTS
gl_EEMALLOC
gl_INIT
CFLAGS=$SAVE_CFLAGS
LIBS=$SAVE_LIBS

View file

@ -765,7 +765,7 @@ xmalloc (size_t size)
val = lmalloc (size, false);
MALLOC_UNBLOCK_INPUT;
if (!val && size)
if (!val)
memory_full (size);
MALLOC_PROBE (size);
return val;
@ -782,7 +782,7 @@ xzalloc (size_t size)
val = lmalloc (size, true);
MALLOC_UNBLOCK_INPUT;
if (!val && size)
if (!val)
memory_full (size);
MALLOC_PROBE (size);
return val;
@ -796,15 +796,15 @@ xrealloc (void *block, size_t size)
void *val;
MALLOC_BLOCK_INPUT;
/* We must call malloc explicitly when BLOCK is 0, since some
reallocs don't do this. */
/* Call lmalloc when BLOCK is null, for the benefit of long-obsolete
platforms lacking support for realloc (NULL, size). */
if (! block)
val = lmalloc (size, false);
else
val = lrealloc (block, size);
MALLOC_UNBLOCK_INPUT;
if (!val && size)
if (!val)
memory_full (size);
MALLOC_PROBE (size);
return val;
@ -988,8 +988,7 @@ record_xmalloc (size_t size)
/* Like malloc but used for allocating Lisp data. NBYTES is the
number of bytes to allocate, TYPE describes the intended use of the
allocated memory block (for strings, for conses, ...).
NBYTES must be positive. */
allocated memory block (for strings, for conses, ...). */
#if ! USE_LSB_TAG
void *lisp_malloc_loser EXTERNALLY_VISIBLE;
@ -1330,16 +1329,20 @@ laligned (void *p, size_t size)
|| size % LISP_ALIGNMENT != 0);
}
/* Like malloc and realloc except that if SIZE is Lisp-aligned, make
sure the result is too, if necessary by reallocating (typically
with larger and larger sizes) until the allocator returns a
Lisp-aligned pointer. Code that needs to allocate C heap memory
/* Like malloc and realloc except return null only on failure,
the result is Lisp-aligned if SIZE is, and lrealloc's pointer
argument must be nonnull. Code allocating C heap memory
for a Lisp object should use one of these functions to obtain a
pointer P; that way, if T is an enum Lisp_Type value and L ==
make_lisp_ptr (P, T), then XPNTR (L) == P and XTYPE (L) == T.
If CLEARIT, arrange for the allocated memory to be cleared.
This might use calloc, as calloc can be faster than malloc+memset.
On typical modern platforms these functions' loops do not iterate.
On now-rare (and perhaps nonexistent) platforms, the loops in
On now-rare (and perhaps nonexistent) platforms, the code can loop,
reallocating (typically with larger and larger sizes) until the
allocator returns a Lisp-aligned pointer. This loop in
theory could repeat forever. If an infinite loop is possible on a
platform, a build would surely loop and the builder can then send
us a bug report. Adding a counter to try to detect any such loop
@ -1353,8 +1356,13 @@ lmalloc (size_t size, bool clearit)
if (! MALLOC_IS_LISP_ALIGNED && size % LISP_ALIGNMENT == 0)
{
void *p = aligned_alloc (LISP_ALIGNMENT, size);
if (clearit && p)
memclear (p, size);
if (p)
{
if (clearit)
memclear (p, size);
}
else if (! (MALLOC_0_IS_NONNULL || size))
return aligned_alloc (LISP_ALIGNMENT, LISP_ALIGNMENT);
return p;
}
#endif
@ -1362,7 +1370,7 @@ lmalloc (size_t size, bool clearit)
while (true)
{
void *p = clearit ? calloc (1, size) : malloc (size);
if (laligned (p, size))
if (laligned (p, size) && (MALLOC_0_IS_NONNULL || size || p))
return p;
free (p);
size_t bigger = size + LISP_ALIGNMENT;
@ -1377,7 +1385,7 @@ lrealloc (void *p, size_t size)
while (true)
{
p = realloc (p, size);
if (laligned (p, size))
if (laligned (p, size) && (size || p))
return p;
size_t bigger = size + LISP_ALIGNMENT;
if (size < bigger)

View file

@ -3947,7 +3947,8 @@ build_string (const char *str)
extern Lisp_Object pure_cons (Lisp_Object, Lisp_Object);
extern Lisp_Object make_vector (ptrdiff_t, Lisp_Object);
extern struct Lisp_Vector *allocate_nil_vector (ptrdiff_t);
extern struct Lisp_Vector *allocate_nil_vector (ptrdiff_t)
ATTRIBUTE_RETURNS_NONNULL;
/* Make an uninitialized vector for SIZE objects. NOTE: you must
be sure that GC cannot happen until the vector is completely
@ -3960,7 +3961,8 @@ extern struct Lisp_Vector *allocate_nil_vector (ptrdiff_t);
allocate_vector has a similar problem. */
extern struct Lisp_Vector *allocate_vector (ptrdiff_t);
extern struct Lisp_Vector *allocate_vector (ptrdiff_t)
ATTRIBUTE_RETURNS_NONNULL;
INLINE Lisp_Object
make_uninit_vector (ptrdiff_t size)
@ -3992,7 +3994,8 @@ make_nil_vector (ptrdiff_t size)
}
extern struct Lisp_Vector *allocate_pseudovector (int, int, int,
enum pvec_type);
enum pvec_type)
ATTRIBUTE_RETURNS_NONNULL;
/* Allocate uninitialized pseudovector with no Lisp_Object slots. */
@ -4024,7 +4027,7 @@ extern void free_cons (struct Lisp_Cons *);
extern void init_alloc_once (void);
extern void init_alloc (void);
extern void syms_of_alloc (void);
extern struct buffer * allocate_buffer (void);
extern struct buffer *allocate_buffer (void) ATTRIBUTE_RETURNS_NONNULL;
extern int valid_lisp_object_p (Lisp_Object);
/* Defined in gmalloc.c. */
@ -4182,7 +4185,8 @@ extern Lisp_Object internal_condition_case_n
(Lisp_Object (*) (ptrdiff_t, Lisp_Object *), ptrdiff_t, Lisp_Object *,
Lisp_Object, Lisp_Object (*) (Lisp_Object, ptrdiff_t, Lisp_Object *));
extern Lisp_Object internal_catch_all (Lisp_Object (*) (void *), void *, Lisp_Object (*) (enum nonlocal_exit, Lisp_Object));
extern struct handler *push_handler (Lisp_Object, enum handlertype);
extern struct handler *push_handler (Lisp_Object, enum handlertype)
ATTRIBUTE_RETURNS_NONNULL;
extern struct handler *push_handler_nosignal (Lisp_Object, enum handlertype);
extern void specbind (Lisp_Object, Lisp_Object);
extern void record_unwind_protect (void (*) (Lisp_Object), Lisp_Object);
@ -4323,9 +4327,10 @@ extern void syms_of_marker (void);
/* Defined in fileio.c. */
extern char *splice_dir_file (char *, char const *, char const *);
extern char *splice_dir_file (char *, char const *, char const *)
ATTRIBUTE_RETURNS_NONNULL;
extern bool file_name_absolute_p (const char *);
extern char const *get_homedir (void);
extern char const *get_homedir (void) ATTRIBUTE_RETURNS_NONNULL;
extern Lisp_Object expand_and_dir_to_file (Lisp_Object);
extern Lisp_Object write_region (Lisp_Object, Lisp_Object, Lisp_Object,
Lisp_Object, Lisp_Object, Lisp_Object,
@ -4479,7 +4484,7 @@ INLINE void fixup_locale (void) {}
INLINE void synchronize_system_messages_locale (void) {}
INLINE void synchronize_system_time_locale (void) {}
#endif
extern char *emacs_strerror (int);
extern char *emacs_strerror (int) ATTRIBUTE_RETURNS_NONNULL;
extern void shut_down_emacs (int, Lisp_Object);
/* True means don't do interactive redisplay and don't change tty modes. */
@ -4545,7 +4550,7 @@ extern void setup_process_coding_systems (Lisp_Object);
extern int emacs_spawn (pid_t *, int, int, int, char **, char **,
const char *, const char *, const sigset_t *);
extern char **make_environment_block (Lisp_Object);
extern char **make_environment_block (Lisp_Object) ATTRIBUTE_RETURNS_NONNULL;
extern void init_callproc_1 (void);
extern void init_callproc (void);
extern void set_initial_environment (void);
@ -4814,17 +4819,24 @@ extern char my_edata[];
extern char my_endbss[];
extern char *my_endbss_static;
extern void *xmalloc (size_t) ATTRIBUTE_MALLOC_SIZE ((1));
extern void *xzalloc (size_t) ATTRIBUTE_MALLOC_SIZE ((1));
extern void *xrealloc (void *, size_t) ATTRIBUTE_ALLOC_SIZE ((2));
extern void *xmalloc (size_t)
ATTRIBUTE_MALLOC_SIZE ((1)) ATTRIBUTE_RETURNS_NONNULL;
extern void *xzalloc (size_t)
ATTRIBUTE_MALLOC_SIZE ((1)) ATTRIBUTE_RETURNS_NONNULL;
extern void *xrealloc (void *, size_t)
ATTRIBUTE_ALLOC_SIZE ((2)) ATTRIBUTE_RETURNS_NONNULL;
extern void xfree (void *);
extern void *xnmalloc (ptrdiff_t, ptrdiff_t) ATTRIBUTE_MALLOC_SIZE ((1,2));
extern void *xnmalloc (ptrdiff_t, ptrdiff_t)
ATTRIBUTE_MALLOC_SIZE ((1,2)) ATTRIBUTE_RETURNS_NONNULL;
extern void *xnrealloc (void *, ptrdiff_t, ptrdiff_t)
ATTRIBUTE_ALLOC_SIZE ((2,3));
extern void *xpalloc (void *, ptrdiff_t *, ptrdiff_t, ptrdiff_t, ptrdiff_t);
ATTRIBUTE_ALLOC_SIZE ((2,3)) ATTRIBUTE_RETURNS_NONNULL;
extern void *xpalloc (void *, ptrdiff_t *, ptrdiff_t, ptrdiff_t, ptrdiff_t)
ATTRIBUTE_RETURNS_NONNULL;
extern char *xstrdup (const char *) ATTRIBUTE_MALLOC;
extern char *xlispstrdup (Lisp_Object) ATTRIBUTE_MALLOC;
extern char *xstrdup (char const *)
ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL;
extern char *xlispstrdup (Lisp_Object)
ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL;
extern void dupstring (char **, char const *);
/* Make DEST a copy of STRING's data. Return a pointer to DEST's terminating
@ -4874,7 +4886,8 @@ extern void init_system_name (void);
enum MAX_ALLOCA { MAX_ALLOCA = 16 * 1024 };
extern void *record_xmalloc (size_t) ATTRIBUTE_ALLOC_SIZE ((1));
extern void *record_xmalloc (size_t)
ATTRIBUTE_ALLOC_SIZE ((1)) ATTRIBUTE_RETURNS_NONNULL;
#define USE_SAFE_ALLOCA \
ptrdiff_t sa_avail = MAX_ALLOCA; \