switch to freeRtos malloc + improve malloc_safe utils, fixed memleak

sipo
Ondřej Hruška 6 years ago
parent 0ef1134aa0
commit ace2bd6357
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 4
      FreeRTOSConfig.h
  2. 13
      comm/messages.c
  3. 26
      cortex_handlers.c
  4. 1
      debug.h
  5. 7
      framework/settings.c
  6. 13
      framework/unit.c
  7. 34
      framework/unit_registry.c
  8. 9
      gex.mk
  9. 3
      platform/plat_compat.h
  10. 8
      units/digital_in/unit_din.c
  11. 8
      units/digital_out/unit_dout.c
  12. 8
      units/i2c/unit_i2c.c
  13. 10
      units/neopixel/unit_neopixel.c
  14. 8
      units/spi/unit_spi.c
  15. 16
      units/test/unit_test.c
  16. 7
      units/usart/unit_usart.c
  17. 11
      utils/cortex_utils.h
  18. 8
      utils/ini_writer.c
  19. 56
      utils/malloc_safe.c
  20. 37
      utils/malloc_safe.h
  21. 5
      utils/snprintf.c

@ -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 )

@ -2,13 +2,14 @@
// Created by MightyPork on 2017/11/21.
//
#include <framework/system_settings.h>
#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;

@ -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****/

@ -8,6 +8,7 @@
#include <inttypes.h>
#include <stddef.h>
#include <stdarg.h>
#include "macro.h"
#if USE_DEBUG_UART

@ -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

@ -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

@ -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)

@ -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

@ -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

@ -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);
}
// ------------------------------------------------------------------------

@ -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);
}
// ------------------------------------------------------------------------

@ -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);
}
// ------------------------------------------------------------------------

@ -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);
}
// ------------------------------------------------------------------------

@ -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);
}
// ------------------------------------------------------------------------

@ -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;

@ -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;
}

@ -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 { \

@ -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 { \

@ -1,48 +1,44 @@
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <inttypes.h>
#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;
}

@ -9,14 +9,35 @@
#include <stdint.h>
#include <stdbool.h>
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

@ -23,6 +23,7 @@
/**** pts: sam2p-specific defines ****/
#include "snprintf.h"
#include "malloc_safe.h"
/* #include <stdarg.h> -- from snprintf.h */
#ifdef NULL /* as on Mac OS/X 10.5.7 <stdlib.h> */
# undef NULL
@ -32,7 +33,7 @@
# define malloc ::operator new
#else
# include <stdlib.h> /* malloc() */
#include <debug.h>
#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;

Loading…
Cancel
Save