summaryrefslogtreecommitdiff
path: root/src/alloc.c
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2021-10-13 11:16:33 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2021-10-13 11:47:20 -0700
commit33525102e728134f5f7399a3490a154bb0078e6d (patch)
tree9d3e90a2cb302e63fce9ba97fd47e2af910567c1 /src/alloc.c
parent8e072e6abef2bf1ec75b7c73883caeb7b7459eb1 (diff)
downloademacs-33525102e728134f5f7399a3490a154bb0078e6d.tar.gz
emacs-33525102e728134f5f7399a3490a154bb0078e6d.tar.bz2
emacs-33525102e728134f5f7399a3490a154bb0078e6d.zip
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>.
Diffstat (limited to 'src/alloc.c')
-rw-r--r--src/alloc.c40
1 files changed, 24 insertions, 16 deletions
diff --git a/src/alloc.c b/src/alloc.c
index 0c04d5cde05..aa790d3afae 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -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)