blob: 8bcd4551bb300db6fa3564f465bad91098d78790 [file] [log] [blame]
/*
*
* Copyright (c) 2020-2021 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* This file contains platform specific implementations for stdlib malloc/calloc/realloc/free
* functions, so that CHIPPlatformMemory* works as intended with the platform's heap.
*/
#include "FreeRTOS.h"
#include "task.h"
#include <cstring>
#include <stdint.h>
#include <stdlib.h>
#ifndef NDEBUG
#include <atomic>
#include <cstdio>
#endif
#include <src/lib/support/logging/CHIPLogging.h>
#if CHIP_CONFIG_MEMORY_DEBUG_DMALLOC
#include <dmalloc.h>
#include <lib/support/SafeInt.h>
#endif // CHIP_CONFIG_MEMORY_DEBUG_DMALLOC
/* Assumes 8bit bytes! */
#define heapBITS_PER_BYTE ((size_t) 8)
/* Define the linked list structure. This is used to link free blocks in order
of their memory address. */
typedef struct A_BLOCK_LINK
{
struct A_BLOCK_LINK * pxNextFreeBlock; /*<< The next free block in the list. */
size_t xBlockSize; /*<< The size of the free block. */
} BlockLink_t;
/* The size of the structure placed at the beginning of each allocated memory
block must by correctly byte aligned. */
static const size_t xHeapStructSize =
(sizeof(BlockLink_t) + ((size_t)(portBYTE_ALIGNMENT - 1))) & ~((size_t) portBYTE_ALIGNMENT_MASK);
/* Gets set to the top bit of an size_t type. When this bit in the xBlockSize
member of an BlockLink_t structure is set then the block belongs to the
application. When the bit is free the block is still part of the free heap
space. */
static size_t xBlockAllocatedBit = ((size_t) 1) << ((sizeof(size_t) * heapBITS_PER_BYTE) - 1);
extern "C" {
/* xPortMallocUsableSize relies on heap4 implementation.
It returns the size of an allocated block and it is
called by __wrap_realloc.
Thus it is validated in __wrap_realloc function that the allocated size
of the old_ptr is smaller than the allocated size of new_ptr */
size_t xPortMallocUsableSize(void * pv)
{
uint8_t * puc = (uint8_t *) pv;
BlockLink_t * pxLink;
void * voidp;
size_t sz = 0;
if (pv != NULL)
{
vTaskSuspendAll();
{
/* The memory being checked will have an BlockLink_t structure immediately
before it. */
puc -= xHeapStructSize;
/* This casting is to keep the compiler from issuing warnings. */
voidp = (void *) puc;
pxLink = (BlockLink_t *) voidp;
/* Check if the block is actually allocated. */
configASSERT((pxLink->xBlockSize & xBlockAllocatedBit) != 0);
configASSERT(pxLink->pxNextFreeBlock == NULL);
sz = (pxLink->xBlockSize & ~xBlockAllocatedBit) - xHeapStructSize;
}
(void) xTaskResumeAll();
}
return sz;
}
void * __wrap_malloc(size_t size)
{
return pvPortMalloc(size);
}
void __wrap_free(void * ptr)
{
vPortFree(ptr);
}
void * __wrap_calloc(size_t num, size_t size)
{
size_t total_size = num * size;
// Handle overflow from (num * size)
if ((size != 0) && ((total_size / size) != num))
{
return nullptr;
}
void * ptr = pvPortMalloc(total_size);
if (ptr)
{
memset(ptr, 0, total_size);
}
else
{
ChipLogError(DeviceLayer, "__wrap_calloc: Could not allocate memory!");
}
return ptr;
}
void * __wrap_realloc(void * ptr, size_t new_size)
{
void * new_ptr = NULL;
if (new_size)
{
size_t old_ptr_size = xPortMallocUsableSize(ptr);
if (new_size <= old_ptr_size)
{
/* Return old pointer if the newly allocated size is smaller
or equal to the allocated size for old_ptr */
return ptr;
}
/* if old_ptr is NULL, then old_ptr_size is zero and new_ptr will be returned */
new_ptr = pvPortMalloc(new_size);
if (!new_ptr)
{
ChipLogError(DeviceLayer, "__wrap_realloc: Could not allocate memory!");
return NULL;
}
memset(reinterpret_cast<uint8_t *>(new_ptr) + old_ptr_size, 0, (new_size - old_ptr_size));
memcpy(new_ptr, ptr, old_ptr_size);
}
vPortFree(ptr);
return new_ptr;
}
void * __wrap__malloc_r(void * REENT, size_t size)
{
return __wrap_malloc(size);
}
void __wrap__free_r(void * REENT, void * ptr)
{
__wrap_free(ptr);
}
void * __wrap__realloc_r(void * REENT, void * ptr, size_t new_size)
{
return __wrap_realloc(ptr, new_size);
}
} // extern "C"