switch to freeRtos malloc + improve malloc_safe utils, fixed memleak

This commit is contained in:
2018-01-14 00:04:53 +01:00
parent 0ef1134aa0
commit ace2bd6357
21 changed files with 152 additions and 140 deletions
+3 -1
View File
@@ -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 )
+7 -6
View File
@@ -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;
+26
View File
@@ -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****/
+1
View File
@@ -8,6 +8,7 @@
#include <inttypes.h>
#include <stddef.h>
#include <stdarg.h>
#include "macro.h"
#if USE_DEBUG_UART
+3 -4
View File
@@ -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
+3 -10
View File
@@ -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
+14 -20
View File
@@ -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)
+6 -3
View File
@@ -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
+2 -1
View File
@@ -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
+3 -5
View File
@@ -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);
}
// ------------------------------------------------------------------------
+3 -5
View File
@@ -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);
}
// ------------------------------------------------------------------------
+3 -5
View File
@@ -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);
}
// ------------------------------------------------------------------------
+4 -6
View File
@@ -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);
}
// ------------------------------------------------------------------------
+3 -5
View File
@@ -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);
}
// ------------------------------------------------------------------------
+7 -9
View File
@@ -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;
+3 -4
View File
@@ -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;
}
-11
View File
@@ -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 { \
+3 -5
View File
@@ -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 { \
+26 -30
View File
@@ -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 *malloc_ck_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 *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;
}
+29 -8
View File
@@ -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
+3 -2
View File
@@ -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;