From: Paul Eggert Date: Mon, 2 Aug 2021 00:35:17 +0000 (-0700) Subject: malloca: improve -fanalyzer malloc checking X-Git-Tag: v1.0~2753 X-Git-Url: https://gitweb.git.savannah.gnu.org/gitweb/?a=commitdiff_plain;h=8c6a99453e4a38fe6b602718e7b5e68444870e07;p=gnulib.git malloca: improve -fanalyzer malloc checking --- diff --git a/ChangeLog b/ChangeLog index 6bad8ceb67..166618a42c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,11 +3,14 @@ maint: improve -fanalyzer malloc checking * lib/backup-internal.h, lib/backupfile.h: * lib/canonicalize.h, lib/dfa.h, lib/dirname.h, lib/exclude.h: - * lib/filenamecat.h: + * lib/filenamecat.h, lib/malloca.h: Add malloc-related attributes and include stdlib.h as needed. * lib/dfa.c: Include verify.h. (assume_nonnull): New macro. (dfamust): Use it to pacify GCC. + * lib/malloca.c (mmalloca): Redo to pacify GCC, to cut down on the + number of casts, and to avoid signed integer overflow on + theoretical platforms. 2021-08-01 Jim Meyering diff --git a/lib/malloca.c b/lib/malloca.c index d7ad095b5a..b4884234a2 100644 --- a/lib/malloca.c +++ b/lib/malloca.c @@ -47,7 +47,8 @@ mmalloca (size_t n) #if HAVE_ALLOCA /* Allocate one more word, used to determine the address to pass to freea(), and room for the alignment ≡ sa_alignment_max mod 2*sa_alignment_max. */ - int plus = sizeof (small_t) + 2 * sa_alignment_max - 1; + uintptr_t alignment2_mask = 2 * sa_alignment_max - 1; + int plus = sizeof (small_t) + alignment2_mask; idx_t nplus; if (!INT_ADD_WRAPV (n, plus, &nplus) && !xalloc_oversized (nplus, 1)) { @@ -55,16 +56,21 @@ mmalloca (size_t n) if (mem != NULL) { - char *p = - (char *)((((uintptr_t)mem + sizeof (small_t) + sa_alignment_max - 1) - & ~(uintptr_t)(2 * sa_alignment_max - 1)) - + sa_alignment_max); + uintptr_t umem = (uintptr_t)mem, umemplus; + /* The INT_ADD_WRAPV avoids signed integer overflow on + theoretical platforms where UINTPTR_MAX <= INT_MAX. */ + INT_ADD_WRAPV (umem, sizeof (small_t) + sa_alignment_max - 1, + &umemplus); + idx_t offset = ((umemplus & ~alignment2_mask) + + sa_alignment_max - umem); + void *vp = mem + offset; + small_t *p = vp; /* Here p >= mem + sizeof (small_t), and p <= mem + sizeof (small_t) + 2 * sa_alignment_max - 1 hence p + n <= mem + nplus. So, the memory range [p, p+n) lies in the allocated memory range [mem, mem + nplus). */ - ((small_t *) p)[-1] = p - mem; + p[-1] = offset; /* p ≡ sa_alignment_max mod 2*sa_alignment_max. */ return p; } diff --git a/lib/malloca.h b/lib/malloca.h index 6fa1d8b205..dbbec3f065 100644 --- a/lib/malloca.h +++ b/lib/malloca.h @@ -65,7 +65,6 @@ extern "C" { # define malloca(N) \ mmalloca (N) #endif -extern void * mmalloca (size_t n); /* Free a block of memory allocated through malloca(). */ #if HAVE_ALLOCA @@ -74,6 +73,10 @@ extern void freea (void *p); # define freea free #endif +extern void *mmalloca (size_t n) + _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC (freea, 1) + _GL_ATTRIBUTE_ALLOC_SIZE ((1)); + /* nmalloca(N,S) is an overflow-safe variant of malloca (N * S). It allocates an array of N objects, each with S bytes of memory, on the stack. N and S should be nonnegative and free of side effects.