1
0
Fork 0
forked from nuttx/nuttx-update

mm: memory allocations return valid pointer when request 0 size

This change introduce 2 items:
1. If the size of the space requested is 0, the behavior is implementation-defined:
   either a null pointer shall be returned, or the behavior shall be as if the size
   were some non-zero value, except that the behavior is undefined if the returned
   pointer is used to access an object.

   Change the behavior to be similar to Linux and Android and allocates an object
   of a minimum size instead of returning null pointer.

   https://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html
   https://pubs.opengroup.org/onlinepubs/9699919799/functions/calloc.html
   https://pubs.opengroup.org/onlinepubs/9699919799/functions/realloc.html

2. The description of realloc() has been modified from previous versions of this
   standard to align with the ISO/IEC 9899:1999 standard. Previous versions explicitly
   permitted a call to realloc (p, 0) to free the space pointed to by p and return
   a null pointer. While this behavior could be interpreted as permitted by this
   version of the standard, the C language committee have indicated that this
   interpretation is incorrect. Applications should assume that if realloc() returns
   a null pointer, the space pointed to by p has not been freed. Since this could lead
   to double-frees, implementations should also set errno if a null pointer actually
   indicates a failure, and applications should only free the space if errno was changed.

   Do not free memory of zero-length reallocation is requested

   https://pubs.opengroup.org/onlinepubs/9699919799/functions/realloc.html

Co-authored-by: fangxinyong <fangxinyong@xiaomi.com>
Signed-off-by: Petro Karashchenko <petro.karashchenko@gmail.com>
This commit is contained in:
Petro Karashchenko 2023-05-02 15:58:22 +03:00 committed by patacongo
parent ea276b20ef
commit 5a298e8685
9 changed files with 61 additions and 86 deletions

View file

@ -406,11 +406,6 @@ FAR void *mempool_multiple_alloc(FAR struct mempool_multiple_s *mpool,
FAR struct mempool_s *end;
FAR struct mempool_s *pool;
if (size < 1)
{
return NULL;
}
pool = mempool_multiple_find(mpool, size);
if (pool == NULL)
{
@ -459,12 +454,6 @@ FAR void *mempool_multiple_realloc(FAR struct mempool_multiple_s *mpool,
return mempool_multiple_alloc(mpool, size);
}
if (size < 1)
{
mempool_multiple_free(mpool, oldblk);
return NULL;
}
dict = mempool_multiple_get_dict(mpool, oldblk);
if (dict == NULL)
{

View file

@ -40,23 +40,22 @@
FAR void *mm_calloc(FAR struct mm_heap_s *heap, size_t n, size_t elem_size)
{
FAR void *ret = NULL;
FAR void *mem = NULL;
/* Verify input parameters */
/* Verify input parameters
*
* elem_size or n is zero treats as valid input.
*
* Assure that the following multiplication cannot overflow the size_t
* type, i.e., that: SIZE_MAX >= n * elem_size
*
* Refer to SEI CERT C Coding Standard.
*/
if (n > 0 && elem_size > 0)
if (elem_size == 0 || n <= (SIZE_MAX / elem_size))
{
/* Assure that the following multiplication cannot overflow the size_t
* type, i.e., that: SIZE_MAX >= n * elem_size
*
* Refer to SEI CERT C Coding Standard.
*/
if (n <= (SIZE_MAX / elem_size))
{
ret = mm_zalloc(heap, n * elem_size);
}
mem = mm_zalloc(heap, n * elem_size);
}
return ret;
return mem;
}

View file

@ -114,13 +114,6 @@ FAR void *mm_malloc(FAR struct mm_heap_s *heap, size_t size)
free_delaylist(heap);
/* Ignore zero-length allocations */
if (size < 1)
{
return NULL;
}
#if CONFIG_MM_HEAP_MEMPOOL_THRESHOLD != 0
ret = mempool_multiple_alloc(heap->mm_mpool, size);
if (ret != NULL)

View file

@ -81,14 +81,6 @@ FAR void *mm_realloc(FAR struct mm_heap_s *heap, FAR void *oldmem,
return mm_malloc(heap, size);
}
/* If size is zero, then realloc is equivalent to free */
if (size < 1)
{
mm_free(heap, oldmem);
return NULL;
}
#if CONFIG_MM_HEAP_MEMPOOL_THRESHOLD != 0
newmem = mempool_multiple_realloc(heap->mm_mpool, oldmem, size);
if (newmem != NULL)

View file

@ -542,25 +542,24 @@ FAR void *mm_brkaddr(FAR struct mm_heap_s *heap, int region)
FAR void *mm_calloc(FAR struct mm_heap_s *heap, size_t n, size_t elem_size)
{
FAR void *ret = NULL;
FAR void *mem = NULL;
/* Verify input parameters */
/* Verify input parameters
*
* elem_size or n is zero treats as valid input.
*
* Assure that the following multiplication cannot overflow the size_t
* type, i.e., that: SIZE_MAX >= n * elem_size
*
* Refer to SEI CERT C Coding Standard.
*/
if (n > 0 && elem_size > 0)
if (elem_size == 0 || n <= (SIZE_MAX / elem_size))
{
/* Assure that the following multiplication cannot overflow the size_t
* type, i.e., that: SIZE_MAX >= n * elem_size
*
* Refer to SEI CERT C Coding Standard.
*/
if (n <= (SIZE_MAX / elem_size))
{
ret = mm_zalloc(heap, n * elem_size);
}
mem = mm_zalloc(heap, n * elem_size);
}
return ret;
return mem;
}
#ifdef CONFIG_DEBUG_MM
@ -1005,6 +1004,13 @@ FAR void *mm_malloc(FAR struct mm_heap_s *heap, size_t size)
{
FAR void *ret;
/* In case of zero-length allocations allocate the minimum size object */
if (size < 1)
{
size = 1;
}
#if CONFIG_MM_HEAP_MEMPOOL_THRESHOLD != 0
ret = mempool_multiple_alloc(heap->mm_mpool, size);
if (ret != NULL)
@ -1124,15 +1130,20 @@ FAR void *mm_realloc(FAR struct mm_heap_s *heap, FAR void *oldmem,
{
FAR void *newmem;
/* If oldmem is NULL, then realloc is equivalent to malloc */
if (oldmem == NULL)
{
return mm_malloc(heap, size);
}
if (size == 0)
/* If size is zero, reallocate to the minim size object, so
* the memory pointed by oldmem is freed
*/
if (size < 1)
{
mm_free(heap, oldmem);
return NULL;
size = 1;
}
#if CONFIG_MM_HEAP_MEMPOOL_THRESHOLD != 0
@ -1155,7 +1166,6 @@ FAR void *mm_realloc(FAR struct mm_heap_s *heap, FAR void *oldmem,
#endif
#ifdef CONFIG_MM_KASAN
newmem = mm_malloc(heap, size);
if (newmem)
{

View file

@ -48,26 +48,25 @@ FAR void *calloc(size_t n, size_t elem_size)
#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_BUILD_KERNEL)
/* Use zalloc() because it implements the sbrk() logic */
FAR void *ret = NULL;
FAR void *mem = NULL;
/* Verify input parameters
*
* elem_size or n is zero treats as valid input.
*
* Assure that the following multiplication cannot overflow the size_t
* type, i.e., that: SIZE_MAX >= n * elem_size
*
* Refer to SEI CERT C Coding Standard.
*/
/* Verify input parameters */
if (n > 0 && elem_size > 0)
if (elem_size == 0 || n <= (SIZE_MAX / elem_size))
{
/* Assure that the following multiplication cannot overflow the size_t
* type, i.e., that: SIZE_MAX >= n * elem_size
*
* Refer to SEI CERT C Coding Standard.
*/
/* Use zalloc() because it implements the sbrk() logic */
if (n <= (SIZE_MAX / elem_size))
{
ret = zalloc(n * elem_size);
}
mem = zalloc(n * elem_size);
}
return ret;
return mem;
#else
/* Use mm_calloc() because it implements the clear */

View file

@ -75,7 +75,7 @@ FAR void *memalign(size_t alignment, size_t size)
mem = mm_memalign(USR_HEAP, alignment, size);
if (!mem)
{
brkaddr = sbrk(size);
brkaddr = sbrk(size < 1 ? 1 : size);
if (brkaddr == (FAR void *)-1)
{
return NULL;

View file

@ -57,12 +57,6 @@ FAR void *realloc(FAR void *oldmem, size_t size)
FAR void *brkaddr;
FAR void *mem;
if (size < 1)
{
mm_free(USR_HEAP, oldmem);
return NULL;
}
/* Initialize the user heap if it wasn't yet */
umm_try_initialize();
@ -83,7 +77,7 @@ FAR void *realloc(FAR void *oldmem, size_t size)
mem = mm_realloc(USR_HEAP, oldmem, size);
if (!mem)
{
brkaddr = sbrk(size);
brkaddr = sbrk(size < 1 ? 1 : size);
if (brkaddr == (FAR void *)-1)
{
return NULL;

View file

@ -55,14 +55,13 @@ FAR void *zalloc(size_t size)
#ifdef CONFIG_ARCH_ADDRENV
/* Use malloc() because it implements the sbrk() logic */
FAR void *alloc = malloc(size);
if (alloc)
FAR void *mem = malloc(size);
if (mem)
{
memset(alloc, 0, size);
memset(mem, 0, size);
}
return alloc;
return mem;
#else
/* Use mm_zalloc() because it implements the clear */