Hi, Philip Withnall wrote: > We’ve seen a compiler warning in the vasnprintf module (as copied into > GLib) when building with GCC 14 (on msys2, although I don’t think > that’s relevant). > > ``` > ../glib/gnulib/vasnprintf.c: In function 'multiply': > ../glib/gnulib/vasnprintf.c:382:21: error: allocation of insufficient > size '1' for type 'mp_limb_t' {aka 'unsigned int'} with size '4' [- > Werror=alloc-size] > 382 | dest->limbs = (mp_limb_t *) malloc (1); > | ^ > cc1.exe: all warnings being treated as errors > ``` > > This is for the following code in vasnprintf.c: > ``` > if (len1 == 0) > { > /* src1 or src2 is zero. */ > dest->nlimbs = 0; > dest->limbs = (mp_limb_t *) malloc (1); > } > ``` > > Given that it’s setting `nlimbs = 0`, I suspect that the allocation is > a dummy and doesn’t actually need to contain a full `mp_limb_t`.
Correct. > The compiler can’t know that though. Correct. Only a runtime instrumentation (like valgrind or ASAN) can distinguish between an allocation need of 0 words vs. 1 word. > The fix we’ve put together for GLib is here, and makes the obvious > switch from allocating one byte to allocating `sizeof (mp_limb_t)`: > https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4066/diffs?commit_id=cbc58085455b699e9ccd73f30eed72510ead5813 This approach has the drawback that runtime instrumentations will not detect if we accidentally read or write the first element of this array. > ... go with an > alternative like using a pragma to ignore the -Walloc-size warning > around that area of code. I considered this. But -Walloc-size is sometimes a useful warning, and 4 to 7 lines of code to disable this warning is a pain. In the end, I'm removing this 'malloc (1)' memory allocation; this should speed up the code in some cases. 2024-05-15 Bruno Haible <br...@clisp.org> vasnprintf: Avoid a dummy memory allocation. * lib/vasnprintf.c (NOMEM_PTR): New macro. (multiply, divide): Return it instead of NULL in case of memory allocation failure. (scale10_round_decimal_decoded): Update. diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c index de20445894..6f06273081 100644 --- a/lib/vasnprintf.c +++ b/lib/vasnprintf.c @@ -408,6 +408,9 @@ is_infinite_or_zerol (long double x) #if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE +/* An indicator for a failed memory allocation. */ +# define NOMEM_PTR ((void *) (-1)) + /* Converting 'long double' to decimal without rare rounding bugs requires real bignums. We use the naming conventions of GNU gmp, but vastly simpler (and slower) algorithms. */ @@ -428,8 +431,8 @@ typedef struct } mpn_t; /* Compute the product of two bignums >= 0. - Return the allocated memory in case of success, NULL in case of memory - allocation failure. */ + Return the allocated memory (possibly NULL) in case of success, NOMEM_PTR + in case of memory allocation failure. */ static void * multiply (mpn_t src1, mpn_t src2, mpn_t *dest) { @@ -457,7 +460,7 @@ multiply (mpn_t src1, mpn_t src2, mpn_t *dest) { /* src1 or src2 is zero. */ dest->nlimbs = 0; - dest->limbs = (mp_limb_t *) malloc (1); + dest->limbs = NULL; } else { @@ -469,7 +472,7 @@ multiply (mpn_t src1, mpn_t src2, mpn_t *dest) dlen = len1 + len2; dp = (mp_limb_t *) malloc (dlen * sizeof (mp_limb_t)); if (dp == NULL) - return NULL; + return NOMEM_PTR; for (k = len2; k > 0; ) dp[--k] = 0; for (i = 0; i < len1; i++) @@ -500,8 +503,8 @@ multiply (mpn_t src1, mpn_t src2, mpn_t *dest) the remainder. Finally, round-to-even is performed: If r > b/2 or if r = b/2 and q is odd, q is incremented. - Return the allocated memory in case of success, NULL in case of memory - allocation failure. */ + Return the allocated memory (possibly NULL) in case of success, NOMEM_PTR + in case of memory allocation failure. */ static void * divide (mpn_t a, mpn_t b, mpn_t *q) { @@ -572,7 +575,7 @@ divide (mpn_t a, mpn_t b, mpn_t *q) final rounding of q.) */ roomptr = (mp_limb_t *) malloc ((a_len + 2) * sizeof (mp_limb_t)); if (roomptr == NULL) - return NULL; + return NOMEM_PTR; /* Normalise a. */ while (a_len > 0 && a_ptr[a_len - 1] == 0) @@ -708,7 +711,7 @@ divide (mpn_t a, mpn_t b, mpn_t *q) if (tmp_roomptr == NULL) { free (roomptr); - return NULL; + return NOMEM_PTR; } { const mp_limb_t *sourceptr = b_ptr; @@ -1306,7 +1309,7 @@ scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n) mpn_t denominator; void *tmp_memory; tmp_memory = multiply (m, pow5, &numerator); - if (tmp_memory == NULL) + if (tmp_memory == NOMEM_PTR) { free (pow5_ptr); free (memory); @@ -1379,7 +1382,7 @@ scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n) /* Here y = round (x * 10^n) = z * 10^extra_zeroes. */ - if (z_memory == NULL) + if (z_memory == NOMEM_PTR) return NULL; digits = convert_to_decimal (z, extra_zeroes); free (z_memory);