aboutsummaryrefslogtreecommitdiffstats
path: root/src/alloc.c
diff options
context:
space:
mode:
authorPaul Eggert2021-10-13 11:16:33 -0700
committerPaul Eggert2021-10-13 11:47:20 -0700
commit33525102e728134f5f7399a3490a154bb0078e6d (patch)
tree9d3e90a2cb302e63fce9ba97fd47e2af910567c1 /src/alloc.c
parent8e072e6abef2bf1ec75b7c73883caeb7b7459eb1 (diff)
downloademacs-33525102e728134f5f7399a3490a154bb0078e6d.tar.gz
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)
765 val = lmalloc (size, false); 765 val = lmalloc (size, false);
766 MALLOC_UNBLOCK_INPUT; 766 MALLOC_UNBLOCK_INPUT;
767 767
768 if (!val && size) 768 if (!val)
769 memory_full (size); 769 memory_full (size);
770 MALLOC_PROBE (size); 770 MALLOC_PROBE (size);
771 return val; 771 return val;
@@ -782,7 +782,7 @@ xzalloc (size_t size)
782 val = lmalloc (size, true); 782 val = lmalloc (size, true);
783 MALLOC_UNBLOCK_INPUT; 783 MALLOC_UNBLOCK_INPUT;
784 784
785 if (!val && size) 785 if (!val)
786 memory_full (size); 786 memory_full (size);
787 MALLOC_PROBE (size); 787 MALLOC_PROBE (size);
788 return val; 788 return val;
@@ -796,15 +796,15 @@ xrealloc (void *block, size_t size)
796 void *val; 796 void *val;
797 797
798 MALLOC_BLOCK_INPUT; 798 MALLOC_BLOCK_INPUT;
799 /* We must call malloc explicitly when BLOCK is 0, since some 799 /* Call lmalloc when BLOCK is null, for the benefit of long-obsolete
800 reallocs don't do this. */ 800 platforms lacking support for realloc (NULL, size). */
801 if (! block) 801 if (! block)
802 val = lmalloc (size, false); 802 val = lmalloc (size, false);
803 else 803 else
804 val = lrealloc (block, size); 804 val = lrealloc (block, size);
805 MALLOC_UNBLOCK_INPUT; 805 MALLOC_UNBLOCK_INPUT;
806 806
807 if (!val && size) 807 if (!val)
808 memory_full (size); 808 memory_full (size);
809 MALLOC_PROBE (size); 809 MALLOC_PROBE (size);
810 return val; 810 return val;
@@ -988,8 +988,7 @@ record_xmalloc (size_t size)
988 988
989/* Like malloc but used for allocating Lisp data. NBYTES is the 989/* Like malloc but used for allocating Lisp data. NBYTES is the
990 number of bytes to allocate, TYPE describes the intended use of the 990 number of bytes to allocate, TYPE describes the intended use of the
991 allocated memory block (for strings, for conses, ...). 991 allocated memory block (for strings, for conses, ...). */
992 NBYTES must be positive. */
993 992
994#if ! USE_LSB_TAG 993#if ! USE_LSB_TAG
995void *lisp_malloc_loser EXTERNALLY_VISIBLE; 994void *lisp_malloc_loser EXTERNALLY_VISIBLE;
@@ -1330,16 +1329,20 @@ laligned (void *p, size_t size)
1330 || size % LISP_ALIGNMENT != 0); 1329 || size % LISP_ALIGNMENT != 0);
1331} 1330}
1332 1331
1333/* Like malloc and realloc except that if SIZE is Lisp-aligned, make 1332/* Like malloc and realloc except return null only on failure,
1334 sure the result is too, if necessary by reallocating (typically 1333 the result is Lisp-aligned if SIZE is, and lrealloc's pointer
1335 with larger and larger sizes) until the allocator returns a 1334 argument must be nonnull. Code allocating C heap memory
1336 Lisp-aligned pointer. Code that needs to allocate C heap memory
1337 for a Lisp object should use one of these functions to obtain a 1335 for a Lisp object should use one of these functions to obtain a
1338 pointer P; that way, if T is an enum Lisp_Type value and L == 1336 pointer P; that way, if T is an enum Lisp_Type value and L ==
1339 make_lisp_ptr (P, T), then XPNTR (L) == P and XTYPE (L) == T. 1337 make_lisp_ptr (P, T), then XPNTR (L) == P and XTYPE (L) == T.
1340 1338
1339 If CLEARIT, arrange for the allocated memory to be cleared.
1340 This might use calloc, as calloc can be faster than malloc+memset.
1341
1341 On typical modern platforms these functions' loops do not iterate. 1342 On typical modern platforms these functions' loops do not iterate.
1342 On now-rare (and perhaps nonexistent) platforms, the loops in 1343 On now-rare (and perhaps nonexistent) platforms, the code can loop,
1344 reallocating (typically with larger and larger sizes) until the
1345 allocator returns a Lisp-aligned pointer. This loop in
1343 theory could repeat forever. If an infinite loop is possible on a 1346 theory could repeat forever. If an infinite loop is possible on a
1344 platform, a build would surely loop and the builder can then send 1347 platform, a build would surely loop and the builder can then send
1345 us a bug report. Adding a counter to try to detect any such loop 1348 us a bug report. Adding a counter to try to detect any such loop
@@ -1353,8 +1356,13 @@ lmalloc (size_t size, bool clearit)
1353 if (! MALLOC_IS_LISP_ALIGNED && size % LISP_ALIGNMENT == 0) 1356 if (! MALLOC_IS_LISP_ALIGNED && size % LISP_ALIGNMENT == 0)
1354 { 1357 {
1355 void *p = aligned_alloc (LISP_ALIGNMENT, size); 1358 void *p = aligned_alloc (LISP_ALIGNMENT, size);
1356 if (clearit && p) 1359 if (p)
1357 memclear (p, size); 1360 {
1361 if (clearit)
1362 memclear (p, size);
1363 }
1364 else if (! (MALLOC_0_IS_NONNULL || size))
1365 return aligned_alloc (LISP_ALIGNMENT, LISP_ALIGNMENT);
1358 return p; 1366 return p;
1359 } 1367 }
1360#endif 1368#endif
@@ -1362,7 +1370,7 @@ lmalloc (size_t size, bool clearit)
1362 while (true) 1370 while (true)
1363 { 1371 {
1364 void *p = clearit ? calloc (1, size) : malloc (size); 1372 void *p = clearit ? calloc (1, size) : malloc (size);
1365 if (laligned (p, size)) 1373 if (laligned (p, size) && (MALLOC_0_IS_NONNULL || size || p))
1366 return p; 1374 return p;
1367 free (p); 1375 free (p);
1368 size_t bigger = size + LISP_ALIGNMENT; 1376 size_t bigger = size + LISP_ALIGNMENT;
@@ -1377,7 +1385,7 @@ lrealloc (void *p, size_t size)
1377 while (true) 1385 while (true)
1378 { 1386 {
1379 p = realloc (p, size); 1387 p = realloc (p, size);
1380 if (laligned (p, size)) 1388 if (laligned (p, size) && (size || p))
1381 return p; 1389 return p;
1382 size_t bigger = size + LISP_ALIGNMENT; 1390 size_t bigger = size + LISP_ALIGNMENT;
1383 if (size < bigger) 1391 if (size < bigger)