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:
parent
ea276b20ef
commit
5a298e8685
9 changed files with 61 additions and 86 deletions
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
Loading…
Reference in a new issue