From ace2bd6357bc7e76184e58e73a7ee5557f1d480f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 14 Jan 2018 00:04:53 +0100 Subject: [PATCH] switch to freeRtos malloc + improve malloc_safe utils, fixed memleak --- FreeRTOSConfig.h | 4 ++- comm/messages.c | 13 ++++---- cortex_handlers.c | 26 ++++++++++++++++ debug.h | 1 + framework/settings.c | 7 ++--- framework/unit.c | 13 ++------ framework/unit_registry.c | 34 +++++++++------------ gex.mk | 9 ++++-- platform/plat_compat.h | 3 +- units/digital_in/unit_din.c | 8 ++--- units/digital_out/unit_dout.c | 8 ++--- units/i2c/unit_i2c.c | 8 ++--- units/neopixel/unit_neopixel.c | 10 +++--- units/spi/unit_spi.c | 8 ++--- units/test/unit_test.c | 16 +++++----- units/usart/unit_usart.c | 7 ++--- utils/cortex_utils.h | 11 ------- utils/ini_writer.c | 8 ++--- utils/malloc_safe.c | 56 ++++++++++++++++------------------ utils/malloc_safe.h | 37 +++++++++++++++++----- utils/snprintf.c | 5 +-- 21 files changed, 152 insertions(+), 140 deletions(-) diff --git a/FreeRTOSConfig.h b/FreeRTOSConfig.h index 2c2a0b7..c56a883 100644 --- a/FreeRTOSConfig.h +++ b/FreeRTOSConfig.h @@ -95,7 +95,7 @@ #define configUSE_PREEMPTION 1 #define configSUPPORT_STATIC_ALLOCATION 1 -#define configSUPPORT_DYNAMIC_ALLOCATION 0 +#define configSUPPORT_DYNAMIC_ALLOCATION 1 #define configUSE_IDLE_HOOK 0 #define configUSE_TICK_HOOK 0 #define configCPU_CLOCK_HZ ( SystemCoreClock ) @@ -109,6 +109,8 @@ #define configCHECK_FOR_STACK_OVERFLOW 2 #define configENABLE_BACKWARD_COMPATIBILITY 0 +#define configTOTAL_HEAP_SIZE 4096 + /* Co-routine definitions. */ #define configUSE_CO_ROUTINES 0 #define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) diff --git a/comm/messages.c b/comm/messages.c index 7583dae..2348ca8 100644 --- a/comm/messages.c +++ b/comm/messages.c @@ -2,13 +2,14 @@ // Created by MightyPork on 2017/11/21. // -#include #include "platform.h" #include "framework/settings.h" #include "utils/ini_parser.h" #include "TinyFrame.h" #include "framework/unit_registry.h" #include "comm/messages.h" +#include "framework/system_settings.h" +#include "utils/malloc_safe.h" static TinyFrame tf_; TinyFrame *comm = &tf_; @@ -61,7 +62,7 @@ static void settings_bulkread_cb(BulkRead *bulk, uint32_t chunk, uint8_t *buffer { // clean-up request if (buffer == NULL) { - free(bulk); + free_ck(bulk); iw_end(); dbg("INI read complete."); return; @@ -80,8 +81,8 @@ static TF_Result lst_ini_export(TinyFrame *tf, TF_Msg *msg) { dbg("Bulk read INI file"); - BulkRead *bulk = malloc(sizeof(BulkRead)); - assert_param(bulk); + BulkRead *bulk = malloc_ck(sizeof(BulkRead)); + assert_param(bulk != NULL); bulk->frame_id = msg->frame_id; bulk->len = iw_measure_total(settings_build_units_ini); @@ -115,7 +116,7 @@ static void settings_bulkwrite_cb(BulkWrite *bulk, const uint8_t *chunk, uint32_ dbg("INI write failed"); } - free(bulk); + free_ck(bulk); return; } @@ -129,7 +130,7 @@ static TF_Result lst_ini_import(TinyFrame *tf, TF_Msg *msg) { dbg("Bulk write INI file"); - BulkWrite *bulk = malloc(sizeof(BulkWrite)); + BulkWrite *bulk = malloc_ck(sizeof(BulkWrite)); assert_param(bulk); bulk->frame_id = msg->frame_id; diff --git a/cortex_handlers.c b/cortex_handlers.c index fc7eb42..6e5584d 100644 --- a/cortex_handlers.c +++ b/cortex_handlers.c @@ -206,5 +206,31 @@ void __attribute__((naked)) HardFault_Handler(void) while (1); } +#if 0 +char *heap_end = 0; +caddr_t _sbrk(int incr) { + extern char _end; // this is the end of bbs, defined in LD + extern char _estack; // this is the end of the allocable memory - defined in LD. Top level stack lives here. + char *prev_heap_end; + + if (heap_end == 0) { + heap_end = &_end; + } + prev_heap_end = heap_end; + + if (heap_end + incr > &_estack) { + /* Heap and stack collision */ + dbg("\r\nOUT OF MEMORY"); + return (char*)-1; + } +#if DEBUG_MALLOC + PRINTF(" !sbrk(%d),total=%d! ", incr, (int)(heap_end - &_end)); +#endif + + heap_end += incr; + return (caddr_t) prev_heap_end; +} +#endif + /* USER CODE END 1 */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/debug.h b/debug.h index 96128e0..65ec0fd 100644 --- a/debug.h +++ b/debug.h @@ -8,6 +8,7 @@ #include #include #include +#include "macro.h" #if USE_DEBUG_UART diff --git a/framework/settings.c b/framework/settings.c index 4536c48..88e50d7 100644 --- a/framework/settings.c +++ b/framework/settings.c @@ -87,11 +87,10 @@ static bool savebuf_ovhandler(PayloadBuilder *pb, uint32_t more) void settings_save(void) { HAL_StatusTypeDef hst; - bool suc; assert_param(save_buffer == NULL); // It must be NULL here - otherwise we have a leak - save_buffer = malloc_ck(FLASH_SAVE_BUF_LEN, &suc); - assert_param(suc); + save_buffer = malloc_ck(FLASH_SAVE_BUF_LEN); + assert_param(save_buffer != NULL); PayloadBuilder pb = pb_start(save_buffer, FLASH_SAVE_BUF_LEN, savebuf_ovhandler); @@ -151,7 +150,7 @@ void settings_save(void) assert_param(hst == HAL_OK); fls_printf("--- Flash done ---\r\n"); - free(save_buffer); + free_ck(save_buffer); save_buffer = NULL; #if DEBUG_FLASH_WRITE diff --git a/framework/unit.c b/framework/unit.c index a1839f4..36da8c3 100644 --- a/framework/unit.c +++ b/framework/unit.c @@ -5,6 +5,7 @@ #include "platform.h" #include "unit.h" #include "resources.h" +#include "unit_base.h" char unit_tmp512[UNIT_TMP_LEN]; @@ -16,16 +17,8 @@ void clean_failed_unit(Unit *unit) dbg("!! Init of [%s] failed!", unit->name); // Free if it looks like it might've been allocated - if (isDynAlloc(unit->data)) { - dbg("Freeing allocated unit data"); - free(unit->data); - unit->data = NULL; - } - if (isDynAlloc(unit->name)) { - dbg("Freeing allocated name"); - free((void *) unit->name); - unit->name = NULL; - } + free_ck(unit->data); + free_ck(unit->name); dbg("Releasing any held resources"); // Release any already claimed resources diff --git a/framework/unit_registry.c b/framework/unit_registry.c index 3773250..2abf654 100644 --- a/framework/unit_registry.c +++ b/framework/unit_registry.c @@ -58,8 +58,8 @@ void ureg_add_type(const UnitDriver *driver) assert_param(driver->deInit != NULL); assert_param(driver->handleRequest != NULL); - UregEntry *re = calloc_ck(1, sizeof(UregEntry), &suc); - assert_param(suc); + UregEntry *re = calloc_ck(1, sizeof(UregEntry)); + assert_param(re != NULL); re->driver = driver; re->next = NULL; @@ -81,11 +81,7 @@ static void free_le_unit(UlistEntry *le) pUnit->driver->deInit(pUnit); // Name is not expected to be freed by the deInit() function // - was alloc'd in the settings load loop - if (isDynAlloc(pUnit->name)) { - dbg("Freeing allocated name"); - free((void *) pUnit->name); - pUnit->name = NULL; - } + free_ck(pUnit->name); } /** Add unit to the list, updating references as needed */ @@ -103,7 +99,6 @@ static void add_unit_to_list(UlistEntry *le) // create a unit instance (not yet loading or initing - just pre-init) Unit *ureg_instantiate(const char *driver_name) { - bool suc = true; error_t rv; // Find type in the repository @@ -111,8 +106,8 @@ Unit *ureg_instantiate(const char *driver_name) while (re != NULL) { if (streq(re->driver->name, driver_name)) { // Create new list entry - UlistEntry *le = calloc_ck(1, sizeof(UlistEntry), &suc); - CHECK_SUC(); + UlistEntry *le = calloc_ck(1, sizeof(UlistEntry)); + if (le == NULL) return NULL; le->next = NULL; @@ -132,7 +127,7 @@ Unit *ureg_instantiate(const char *driver_name) dbg("!! Unit type %s failed to pre-init! %s", driver_name, error_get_message(rv)); clean_failed_unit(pUnit); - free(le); + free_ck(le); return NULL; } @@ -211,7 +206,7 @@ bool ureg_load_units(PayloadParser *pp) // NAME pp_string(pp, typebuf, 16); - pUnit->name = strdup(typebuf); + pUnit->name = strdup_ck(typebuf); assert_param(pUnit->name); // callsign @@ -247,7 +242,7 @@ void ureg_remove_all_units(void) next = le->next; free_le_unit(le); - free(le); + free_ck(le); le = next; } @@ -274,17 +269,17 @@ bool ureg_instantiate_by_ini(const char *restrict driver_name, const char *restr char *name = NULL; if (delim != NULL) { // not last - name = strndup(p, delim - p); + name = strndup_ck(p, delim - p); p = delim + 1; } else { // last name - name = strdup(p); + name = strdup_ck(p); p = NULL; // quit after this loop ends } assert_param(name); Unit *pUnit = ureg_instantiate(driver_name); if (!pUnit) { - free(name); + free_ck(name); return false; } @@ -514,9 +509,8 @@ void ureg_report_active_units(TF_ID frame_id) } msglen += count; // one byte per message for the callsign - bool suc = true; - uint8_t *buff = calloc_ck(1, msglen, &suc); - if (!suc) { + uint8_t *buff = calloc_ck(1, msglen); + if (buff == NULL) { com_respond_error(frame_id, E_OUT_OF_MEM); return; } @@ -539,7 +533,7 @@ void ureg_report_active_units(TF_ID frame_id) com_respond_buf(frame_id, MSG_SUCCESS, buff, msglen); } - free(buff); + free_ck(buff); } Unit *ureg_get_rsc_owner(Resource resource) diff --git a/gex.mk b/gex.mk index e3bf971..2d48208 100644 --- a/gex.mk +++ b/gex.mk @@ -57,7 +57,8 @@ GEX_CFLAGS = \ -MD -Wno-redundant-decls -Wno-unused-parameter \ -Wno-unused-variable -Wno-inline \ -fmerge-constants -fmerge-all-constants -Wno-implicit-fallthrough \ - -fno-exceptions -finline-small-functions -findirect-inlining -Wno-strict-aliasing -Wno-float-equal -Wno-discarded-qualifiers -fstack-usage + -fno-exceptions -finline-small-functions -findirect-inlining -Wno-strict-aliasing -Wno-float-equal \ + -Wno-discarded-qualifiers -fstack-usage GEX_CDEFS_BASE = \ -D__weak="__attribute__((weak))" \ @@ -75,7 +76,8 @@ GEX_CDEFS = $(GEX_CDEFS_BASE) \ -DDEBUG_FLASH_WRITE=0 \ -DVERBOSE_HARDFAULT=0 \ -DUSE_STACK_MONITOR=0 \ - -DUSE_DEBUG_UART=0 + -DUSE_DEBUG_UART=0 \ + -DDEBUG_MALLOC=0 else @@ -86,7 +88,8 @@ GEX_CDEFS = $(GEX_CDEFS_BASE) \ -DDEBUG_FLASH_WRITE=0 \ -DVERBOSE_HARDFAULT=1 \ -DUSE_STACK_MONITOR=1 \ - -DUSE_DEBUG_UART=1 + -DUSE_DEBUG_UART=1 \ + -DDEBUG_MALLOC=0 endif diff --git a/platform/plat_compat.h b/platform/plat_compat.h index 894254d..2ef70c4 100644 --- a/platform/plat_compat.h +++ b/platform/plat_compat.h @@ -15,7 +15,8 @@ #define TSK_STACK_MAIN 160 #endif -#define TSK_STACK_MSG 180 // TF message handler task stack size (all unit commands run on this thread) +// 180 is normally enough if not doing extensive debug logging +#define TSK_STACK_MSG 200 // TF message handler task stack size (all unit commands run on this thread) #define BULK_READ_BUF_LEN 256 // Buffer for TF bulk reads #define UNIT_TMP_LEN 512 // Buffer for internal unit operations diff --git a/units/digital_in/unit_din.c b/units/digital_in/unit_din.c index 049da57..b64f679 100644 --- a/units/digital_in/unit_din.c +++ b/units/digital_in/unit_din.c @@ -103,9 +103,8 @@ static void DI_writeIni(Unit *unit, IniWriter *iw) /** Allocate data structure and set defaults */ static error_t DI_preInit(Unit *unit) { - bool suc = true; - struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv), &suc); - if (!suc) return E_OUT_OF_MEM; + struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv)); + if (priv == NULL) return E_OUT_OF_MEM; // some defaults priv->port_name = 'A'; @@ -167,8 +166,7 @@ static void DI_deInit(Unit *unit) rsc_teardown(unit); // Free memory - free(unit->data); - unit->data = NULL; + free_ck(unit->data); } // ------------------------------------------------------------------------ diff --git a/units/digital_out/unit_dout.c b/units/digital_out/unit_dout.c index 141a3db..89ff92f 100644 --- a/units/digital_out/unit_dout.c +++ b/units/digital_out/unit_dout.c @@ -96,9 +96,8 @@ static void DO_writeIni(Unit *unit, IniWriter *iw) /** Allocate data structure and set defaults */ static error_t DO_preInit(Unit *unit) { - bool suc = true; - struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv), &suc); - if (!suc) return E_OUT_OF_MEM; + struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv)); + if (priv == NULL) return E_OUT_OF_MEM; // some defaults priv->port_name = 'A'; @@ -153,8 +152,7 @@ static void DO_deInit(Unit *unit) rsc_teardown(unit); // Free memory - free(unit->data); - unit->data = NULL; + free_ck(unit->data); } // ------------------------------------------------------------------------ diff --git a/units/i2c/unit_i2c.c b/units/i2c/unit_i2c.c index 19b9da4..2c99494 100644 --- a/units/i2c/unit_i2c.c +++ b/units/i2c/unit_i2c.c @@ -129,9 +129,8 @@ static void UI2C_writeIni(Unit *unit, IniWriter *iw) /** Allocate data structure and set defaults */ static error_t UI2C_preInit(Unit *unit) { - bool suc = true; - struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv), &suc); - if (!suc) return E_OUT_OF_MEM; + struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv)); + if (priv == NULL) return E_OUT_OF_MEM; // some defaults priv->periph_num = 1; @@ -282,8 +281,7 @@ static void UI2C_deInit(Unit *unit) rsc_teardown(unit); // Free memory - free(unit->data); - unit->data = NULL; + free_ck(unit->data); } // ------------------------------------------------------------------------ diff --git a/units/neopixel/unit_neopixel.c b/units/neopixel/unit_neopixel.c index 585fdf2..ead4d3e 100644 --- a/units/neopixel/unit_neopixel.c +++ b/units/neopixel/unit_neopixel.c @@ -79,11 +79,10 @@ static void Npx_writeIni(Unit *unit, IniWriter *iw) /** Allocate data structure and set defaults */ static error_t Npx_preInit(Unit *unit) { - bool suc = true; - struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv), &suc); - if (!suc) return E_OUT_OF_MEM; + struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv)); + if (priv == NULL) - // some defaults + // some defaults priv->pin_number = 0; priv->port_name = 'A'; priv->pixels = 1; @@ -127,8 +126,7 @@ static void Npx_deInit(Unit *unit) rsc_teardown(unit); // Free memory - free(unit->data); - unit->data = NULL; + free_ck(unit->data); } // ------------------------------------------------------------------------ diff --git a/units/spi/unit_spi.c b/units/spi/unit_spi.c index 405e154..6fc44ae 100644 --- a/units/spi/unit_spi.c +++ b/units/spi/unit_spi.c @@ -169,9 +169,8 @@ static void USPI_writeIni(Unit *unit, IniWriter *iw) /** Allocate data structure and set defaults */ static error_t USPI_preInit(Unit *unit) { - bool suc = true; - struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv), &suc); - if (!suc) return E_OUT_OF_MEM; + struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv)); + if (priv == NULL) return E_OUT_OF_MEM; // some defaults priv->periph_num = 1; @@ -359,8 +358,7 @@ static void USPI_deInit(Unit *unit) rsc_teardown(unit); // Free memory - free(unit->data); - unit->data = NULL; + free_ck(unit->data); } // ------------------------------------------------------------------------ diff --git a/units/test/unit_test.c b/units/test/unit_test.c index 51ce0b6..322daf6 100644 --- a/units/test/unit_test.c +++ b/units/test/unit_test.c @@ -50,9 +50,8 @@ static void Tst_writeIni(Unit *unit, IniWriter *iw) /** Allocate data structure and set defaults */ static error_t Tst_preInit(Unit *unit) { - bool suc = true; - struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv), &suc); - if (!suc) return E_OUT_OF_MEM; + struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv)); + if (priv == NULL) return E_OUT_OF_MEM; // @@ -78,8 +77,7 @@ static void Tst_deInit(Unit *unit) // // Free memory - free(unit->data); - unit->data = NULL; + free_ck(unit->data); } // ------------------------------------------------------------------------ @@ -98,7 +96,7 @@ static void br_longtext(struct bulk_read *bulk, uint32_t chunk, uint8_t *buffer) { // clean-up request if (buffer == NULL) { - free(bulk); + free_ck(bulk); return; } @@ -109,7 +107,7 @@ static void bw_dump(struct bulk_write *bulk, const uint8_t *chunk, uint32_t len) { // clean-up request if (chunk == NULL) { - free(bulk); + free_ck(bulk); return; } @@ -133,7 +131,7 @@ static error_t Tst_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Pa return E_SUCCESS; case CMD_BULKREAD:; - BulkRead *br = malloc(sizeof(struct bulk_read)); + BulkRead *br = malloc_ck(sizeof(struct bulk_read)); assert_param(br); br->len = (uint32_t) strlen(longtext); @@ -144,7 +142,7 @@ static error_t Tst_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Pa return E_SUCCESS; case CMD_BULKWRITE:; - BulkWrite *bw = malloc(sizeof(struct bulk_write)); + BulkWrite *bw = malloc_ck(sizeof(struct bulk_write)); assert_param(bw); bw->len = 10240; diff --git a/units/usart/unit_usart.c b/units/usart/unit_usart.c index 728e739..5fd9fb0 100644 --- a/units/usart/unit_usart.c +++ b/units/usart/unit_usart.c @@ -42,9 +42,8 @@ struct priv { /** Allocate data structure and set defaults */ static error_t UUSART_preInit(Unit *unit) { - bool suc = true; - struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv), &suc); - if (!suc) return E_OUT_OF_MEM; + struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv)); + if (priv == NULL) return E_OUT_OF_MEM; // some defaults priv->periph_num = 1; @@ -618,7 +617,7 @@ static void UUSART_deInit(Unit *unit) rsc_teardown(unit); // Free memory - free(unit->data); + free_ck(unit->data); unit->data = NULL; } diff --git a/utils/cortex_utils.h b/utils/cortex_utils.h index 1a4db8a..d52cc7a 100644 --- a/utils/cortex_utils.h +++ b/utils/cortex_utils.h @@ -12,17 +12,6 @@ static inline bool inIRQ(void) return __get_IPSR() != 0; } -register char *__SP asm("sp"); - -static inline bool isDynAlloc(const void *obj) -{ - // this is the 0x20000000-something address that should correspond to heap bottom - extern char heapstart __asm("end"); - - return ((uint32_t)obj >= (uint32_t)&heapstart) - && ((uint32_t)obj < (uint32_t)__SP); -} - /** Tight asm loop */ #define __asm_loop(cycles) \ do { \ diff --git a/utils/ini_writer.c b/utils/ini_writer.c index 299d564..ab4e83d 100644 --- a/utils/ini_writer.c +++ b/utils/ini_writer.c @@ -23,17 +23,15 @@ char *iwbuffer = NULL; void iw_begin(void) { assert_param(iwbuffer == NULL); - bool suc = true; - iwbuffer = malloc_ck(IWBUFFER_LEN, &suc); - assert_param(suc); + iwbuffer = malloc_ck(IWBUFFER_LEN); + assert_param(iwbuffer != NULL); } /** Release the helper buffer */ void iw_end(void) { assert_param(iwbuffer != NULL); - free(iwbuffer); - iwbuffer = NULL; + free_ck(iwbuffer); } #define IW_VPRINTF() do { \ diff --git a/utils/malloc_safe.c b/utils/malloc_safe.c index 1cc187a..d14929a 100644 --- a/utils/malloc_safe.c +++ b/utils/malloc_safe.c @@ -1,48 +1,44 @@ -#include -#include -#include -#include +#include "platform.h" #include "debug.h" #include "stm32_assert.h" #include "malloc_safe.h" -#if 1 - -void *malloc_safe_do(size_t size, const char *file, uint32_t line) -{ - void *mem = malloc(size); - if (mem == NULL) abort_msg("MALLOC FAILED", file, line); - return mem; -} - -void *calloc_safe_do(size_t nmemb, size_t size, const char *file, uint32_t line) +void *malloc_ck_do(size_t size, const char *file, uint32_t line) { - void *mem = calloc(size, nmemb); - if (mem == NULL) abort_msg("CALLOC FAILED", file, line); - return mem; -} - - -void *malloc_ck_do(size_t size, bool *suc, const char *file, uint32_t line) -{ - void *mem = malloc(size); + void *mem = pvPortMalloc(size); + _malloc_trace(size, mem, file, line); if (mem == NULL) { warn_msg("MALLOC FAILED", file, line); - *suc = false; - mem = NULL; } return mem; } -void *calloc_ck_do(size_t nmemb, size_t size, bool *suc, const char *file, uint32_t line) +void *calloc_ck_do(size_t nmemb, size_t size, const char *file, uint32_t line) { - void *mem = calloc(size, nmemb); + void *mem = pvPortMalloc(size*nmemb); + _malloc_trace(nmemb*size, mem, file, line); if (mem == NULL) { warn_msg("CALLOC FAILED", file, line); - *suc = false; - mem = NULL; } + memset(mem, 0, size*nmemb); return mem; } -#endif +char *strdup_ck_do(const char *s, const char* file, uint32_t line) +{ + size_t len = strlen(s) + 1; + void *new = malloc_ck_do(len, file, line); + if (new == NULL) return NULL; + return (char *) memcpy (new, s, len); +} + +char *strndup_ck_do(const char *s, uint32_t len, const char* file, uint32_t line) +{ + // TODO verify - this was not tested + size_t alen = MIN(strlen(s) + 1, len); + uint8_t *new = malloc_ck_do(alen, file, line); + if (new == NULL) return NULL; + memcpy (new, s, alen-1); + new[alen-1] = '\0'; + return (char *) new; +} diff --git a/utils/malloc_safe.h b/utils/malloc_safe.h index 501f80c..da3a6bd 100644 --- a/utils/malloc_safe.h +++ b/utils/malloc_safe.h @@ -9,14 +9,35 @@ #include #include -void *malloc_safe_do(size_t size, const char* file, uint32_t line) __attribute__((malloc)); -void *calloc_safe_do(size_t nmemb, size_t size, const char* file, uint32_t line) __attribute__((malloc)); -void *malloc_ck_do(size_t size, bool *suc, const char* file, uint32_t line) __attribute__((malloc)); -void *calloc_ck_do(size_t nmemb, size_t size, bool *suc, const char* file, uint32_t line) __attribute__((malloc)); +void *malloc_ck_do(size_t size, const char* file, uint32_t line) __attribute__((malloc)); +void *calloc_ck_do(size_t nmemb, size_t size, const char* file, uint32_t line) __attribute__((malloc)); +char *strdup_ck_do(const char *s, const char* file, uint32_t line) __attribute__((malloc)); +char *strndup_ck_do(const char *s, uint32_t len, const char* file, uint32_t line) __attribute__((malloc)); -#define malloc_s(size) malloc_safe_do(size, __BASE_FILE__, __LINE__) -#define calloc_s(nmemb, size) calloc_safe_do(nmemb, size, __BASE_FILE__, __LINE__) -#define malloc_ck(size, suc) malloc_ck_do(size, suc, __BASE_FILE__, __LINE__) -#define calloc_ck(nmemb, size, suc) calloc_ck_do(nmemb, size, suc, __BASE_FILE__, __LINE__) +#if DEBUG_MALLOC + + #define _malloc_trace(len, obj, file, line) do { PRINTF("~ malloc(%d) -> 0x%p at ", len, obj); PUTS(file); PUTCHAR(':'); PRINTF("%d\r\n", (int)line); } while (0) + #define _free_trace(obj, file, line) do { PRINTF("~ free(0x%p) at ", obj); PUTS(file); PUTCHAR(':'); PRINTF("%d\r\n", (int)line); } while (0) + #define malloc_ck(size) malloc_ck_do(size, __BASE_FILE__, __LINE__) + #define calloc_ck(nmemb, size) calloc_ck_do(nmemb, size, __BASE_FILE__, __LINE__) + #define strdup_ck(s) strdup_ck_do(s, __BASE_FILE__, __LINE__) + #define strndup_ck(s, len) strndup_ck_do(s, (uint32_t)(len), __BASE_FILE__, __LINE__) +#else + #define _malloc_trace(len, obj, file, line) + #define _free_trace(obj, file, line) + #define malloc_ck(size) malloc_ck_do(size, "", 0) + #define calloc_ck(nmemb, size) calloc_ck_do(nmemb, size, "", 0) + #define strdup_ck(s) strdup_ck_do(s, "", 0) + #define strndup_ck(s, len) strndup_ck_do(s, (uint32_t)(len), "", 0) +#endif + +/** + * Free an allocated object, and assign it to NULL. + */ +#define free_ck(obj) do { \ + _free_trace(obj, __BASE_FILE__, __LINE__); \ + if ((obj) != NULL) vPortFree((void *)(obj)); \ + obj = NULL; \ +} while (0) #endif // MALLOC_SAFE_H diff --git a/utils/snprintf.c b/utils/snprintf.c index 1600738..d9f2ed3 100644 --- a/utils/snprintf.c +++ b/utils/snprintf.c @@ -23,6 +23,7 @@ /**** pts: sam2p-specific defines ****/ #include "snprintf.h" +#include "malloc_safe.h" /* #include -- from snprintf.h */ #ifdef NULL /* as on Mac OS/X 10.5.7 */ # undef NULL @@ -32,7 +33,7 @@ # define malloc ::operator new #else # include /* malloc() */ -#include +#include "debug.h" #endif #define size_t size_t /* normally: int, unsigned */ @@ -834,7 +835,7 @@ size_t vasprintf(char **ptr, const char *format, va_list ap) ret = vsnprintf((char*)NULL, 0, format, ap); if (ret+1 <= 1) return ret; /* pts: bit of old unsigned trick... */ - if (NULL==(*ptr = (char *)malloc(ret+1))) return (size_t)-1; + if (NULL==(*ptr = (char *)malloc_ck(ret+1))) return (size_t)-1; ret = vsnprintf(*ptr, ret+1, format, ap); return ret;