/* Memory allocation with expensive empty allocations. Copyright (C) 2003, 2008, 2010-2024 Free Software Foundation, Inc. Written by Bruno Haible , 2003, based on prior work by Jim Meyering. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #ifndef _EEALLOC_H #define _EEALLOC_H /* malloc (0) and realloc (NULL, 0) can return NULL even when memory is available; see ISO C 23 sections 7.24.3. When P is non-null realloc (P, 0) is worse, in that C23 says the behavior is undefined whereas POSIX.1-2024 (which extends C17) says that realloc (P, 0) when successful behaves like either (free (P), errno = EINVAL, NULL), or like (free (P), malloc (1)) returning non-null so long as you do not dereference the non-null pointer; and glibc does not conform to POSIX as it behaves like (free (P), NULL). There are similar issues with reallocarray. This behavior is sometimes unwelcome, as it entails extra checking to avoid confusing a zero-sized allocation with memory exhaustion, and to avoid undefined behavior in C23. This file provides malloc and realloc workalikes that consistently treat zero sizes as requests for zero-sized allocations instead of for null pointers. However, it does not provide workalikes for related functions like aligned_alloc, calloc, and reallocarray. */ /* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE, _GL_ATTRIBUTE_ALLOC_SIZE, _GL_ATTRIBUTE_MALLOC. */ #if !_GL_CONFIG_H_INCLUDED #error "Please include config.h first." #endif #include #if defined __CHERI_PURE_CAPABILITY__ # include #endif _GL_INLINE_HEADER_BEGIN #ifndef EEALLOC_INLINE # define EEALLOC_INLINE _GL_INLINE #endif #ifdef __cplusplus extern "C" { #endif #if MALLOC_0_IS_NONNULL # define eemalloc malloc #else EEALLOC_INLINE void *eemalloc (size_t n) _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_ALLOC_SIZE ((1)) _GL_ATTRIBUTE_DEALLOC_FREE; EEALLOC_INLINE void * eemalloc (size_t n) { /* If n is zero, allocate a 1-byte block. */ size_t nx = n; if (n == 0) nx = 1; void *ptr = malloc (nx); # if defined __CHERI_PURE_CAPABILITY__ if (ptr != NULL) ptr = cheri_bounds_set (ptr, n); # endif return ptr; } #endif #if REALLOC_0_IS_NONNULL # define eerealloc realloc #else EEALLOC_INLINE void *eerealloc (void *p, size_t n) _GL_ATTRIBUTE_ALLOC_SIZE ((2)); EEALLOC_INLINE void * eerealloc (void *p, size_t n) { /* Work around realloc glitch by treating a 0 size as if it were 1, to avoid undefined behavior in strict C23 platforms, and so that returning NULL is equivalent to failing. */ void *ptr = realloc (p, n ? n : 1); # if defined __CHERI_PURE_CAPABILITY__ if (ptr != NULL) ptr = cheri_bounds_set (ptr, n); # endif return ptr; } #endif /* Maybe we should also define variants eenmalloc (size_t n, size_t s) - behaves like eemalloc (n * s) eezalloc (size_t n) - like eemalloc followed by memset 0 eecalloc (size_t n, size_t s) - like eemalloc (n * s) followed by memset 0 eenrealloc (void *p, size_t n, size_t s) - like eerealloc (p, n * s) If this would be useful in your application. please speak up. */ #ifdef __cplusplus } #endif _GL_INLINE_HEADER_END #endif /* _EEALLOC_H */