return 0;
}
-void *__ec_malloc(size_t size)
+void ec_malloc_unregister(void)
{
- return ec_malloc_handler.malloc(size);
+ ec_malloc_handler.malloc = NULL;
+ ec_malloc_handler.free = NULL;
+ ec_malloc_handler.realloc = NULL;
}
-void __ec_free(void *ptr)
+void *__ec_malloc(size_t size, const char *file, unsigned int line)
{
- ec_malloc_handler.free(ptr);
+ return ec_malloc_handler.malloc(size, file, line);
}
-void *__ec_calloc(size_t nmemb, size_t size)
+void __ec_free(void *ptr, const char *file, unsigned int line)
+{
+ ec_malloc_handler.free(ptr, file, line);
+}
+
+void *__ec_calloc(size_t nmemb, size_t size, const char *file,
+ unsigned int line)
{
void *ptr;
size_t total;
return NULL;
}
- ptr = __ec_malloc(total);
+ ptr = __ec_malloc(total, file, line);
if (ptr == NULL)
return NULL;
return ptr;
}
-void *__ec_realloc(void *ptr, size_t size)
+void *__ec_realloc(void *ptr, size_t size, const char *file, unsigned int line)
{
- return ec_malloc_handler.realloc(ptr, size);
+ return ec_malloc_handler.realloc(ptr, size, file, line);
}
-char *__ec_strdup(const char *s)
+char *__ec_strdup(const char *s, const char *file, unsigned int line)
{
size_t sz = strlen(s) + 1;
char *s2;
- s2 = __ec_malloc(sz);
+ s2 = __ec_malloc(sz, file, line);
if (s2 == NULL)
return NULL;
return s2;
}
-char *__ec_strndup(const char *s, size_t n)
+char *__ec_strndup(const char *s, size_t n, const char *file, unsigned int line)
{
size_t sz = strnlen(s, n);
char *s2;
- s2 = __ec_malloc(sz + 1);
+ s2 = __ec_malloc(sz + 1, file, line);
if (s2 == NULL)
return NULL;
#include <sys/types.h>
-typedef void *(*ec_malloc_t)(size_t size);
-typedef void (*ec_free_t)(void *ptr);
-typedef void *(*ec_realloc_t)(void *ptr, size_t size);
+typedef void *(*ec_malloc_t)(size_t size, const char *file, unsigned int line);
+typedef void (*ec_free_t)(void *ptr, const char *file, unsigned int line);
+typedef void *(*ec_realloc_t)(void *ptr, size_t size, const char *file,
+ unsigned int line);
struct ec_malloc_handler {
ec_malloc_t malloc;
int ec_malloc_register(ec_malloc_t usr_malloc, ec_free_t usr_free,
ec_realloc_t usr_realloc);
+void ec_malloc_unregister(void);
/* internal */
-void *__ec_malloc(size_t size);
-void __ec_free(void *ptr);
-void *__ec_calloc(size_t nmemb, size_t size);
-void *__ec_realloc(void *ptr, size_t size);
-char *__ec_strdup(const char *s);
-char *__ec_strndup(const char *s, size_t n);
+void *__ec_malloc(size_t size, const char *file, unsigned int line);
+void __ec_free(void *ptr, const char *file, unsigned int line);
+void *__ec_calloc(size_t nmemb, size_t size, const char *file,
+ unsigned int line);
+void *__ec_realloc(void *ptr, size_t size, const char *file, unsigned int line);
+char *__ec_strdup(const char *s, const char *file, unsigned int line);
+char *__ec_strndup(const char *s, size_t n, const char *file,
+ unsigned int line);
/* we use macros here to ensure the file/line stay correct when
* debugging the standard malloc with valgrind */
-#define ec_malloc(sz) ({ \
- void *ret_; \
- if (ec_malloc_handler.malloc == NULL) \
- ret_ = malloc(sz); \
- else \
- ret_ = __ec_malloc(sz); \
- ret_; \
+#define ec_malloc(sz) ({ \
+ void *ret_; \
+ if (ec_malloc_handler.malloc == NULL) \
+ ret_ = malloc(sz); \
+ else \
+ ret_ = __ec_malloc(sz, __FILE__, __LINE__); \
+ ret_; \
})
-#define ec_free(ptr) ({ \
- if (ec_malloc_handler.free == NULL) \
- free(ptr); \
- else \
- __ec_free(ptr); \
+#define ec_free(ptr) ({ \
+ if (ec_malloc_handler.free == NULL) \
+ free(ptr); \
+ else \
+ __ec_free(ptr, __FILE__, __LINE__); \
})
-#define ec_realloc(ptr, sz) ({ \
- void *ret_; \
- if (ec_malloc_handler.realloc == NULL) \
- ret_ = realloc(ptr, sz); \
- else \
- ret_ = __ec_realloc(ptr, sz); \
- ret_; \
+#define ec_realloc(ptr, sz) ({ \
+ void *ret_; \
+ if (ec_malloc_handler.realloc == NULL) \
+ ret_ = realloc(ptr, sz); \
+ else \
+ ret_ = __ec_realloc(ptr, sz, __FILE__, __LINE__); \
+ ret_; \
})
-#define ec_calloc(n, sz) ({ \
- void *ret_; \
- if (ec_malloc_handler.malloc == NULL) \
- ret_ = calloc(n, sz); \
- else \
- ret_ = __ec_calloc(n, sz); \
- ret_; \
+#define ec_calloc(n, sz) ({ \
+ void *ret_; \
+ if (ec_malloc_handler.malloc == NULL) \
+ ret_ = calloc(n, sz); \
+ else \
+ ret_ = __ec_calloc(n, sz, __FILE__, __LINE__); \
+ ret_; \
})
-#define ec_strdup(s) ({ \
- void *ret_; \
- if (ec_malloc_handler.malloc == NULL) \
- ret_ = strdup(s); \
- else \
- ret_ = __ec_strdup(s); \
- ret_; \
+#define ec_strdup(s) ({ \
+ void *ret_; \
+ if (ec_malloc_handler.malloc == NULL) \
+ ret_ = strdup(s); \
+ else \
+ ret_ = __ec_strdup(s, __FILE__, __LINE__); \
+ ret_; \
})
-#define ec_strndup(s, n) ({ \
- void *ret_; \
- if (ec_malloc_handler.malloc == NULL) \
- ret_ = strndup(s, n); \
- else \
- ret_ = __ec_strndup(s, n); \
- ret_; \
+#define ec_strndup(s, n) ({ \
+ void *ret_; \
+ if (ec_malloc_handler.malloc == NULL) \
+ ret_ = strndup(s, n); \
+ else \
+ ret_ = __ec_strndup(s, n, __FILE__, __LINE__); \
+ ret_; \
})
#include <stdio.h>
#include <string.h>
+#include <ecoli_malloc.h>
#include <ecoli_test.h>
#include <ecoli_tk.h>
return ret;
}
+TAILQ_HEAD(debug_alloc_hdr_list, debug_alloc_hdr);
+static struct debug_alloc_hdr_list debug_alloc_hdr_list =
+ TAILQ_HEAD_INITIALIZER(debug_alloc_hdr_list);
+
+struct debug_alloc_hdr {
+ TAILQ_ENTRY(debug_alloc_hdr) next;
+ const char *file;
+ unsigned int line;
+ size_t size;
+ unsigned int cookie;
+};
+
+static void *debug_malloc(size_t size, const char *file, unsigned int line)
+{
+ struct debug_alloc_hdr *hdr;
+ size_t new_size = size + sizeof(*hdr) + sizeof(unsigned int);
+ void *ret;
+
+ hdr = malloc(new_size);
+ if (hdr == NULL) {
+ ret = NULL;
+ } else {
+ hdr->file = file;
+ hdr->line = line;
+ hdr->size = size;
+ hdr->cookie = 0x12345678;
+ TAILQ_INSERT_TAIL(&debug_alloc_hdr_list, hdr, next);
+ ret = hdr + 1;
+ }
+
+ printf("%s:%d: info: malloc(%zd) -> %p\n", file, line, size, ret);
+
+ return ret;
+}
+
+static void debug_free(void *ptr, const char *file, unsigned int line)
+{
+ struct debug_alloc_hdr *hdr, *h;
+
+ (void)file;
+ (void)line;
+
+ printf("%s:%d: info: free(%p)\n", file, line, ptr);
+
+ if (ptr == NULL)
+ return;
+
+ hdr = (ptr - sizeof(*hdr));
+ if (hdr->cookie != 0x12345678) {
+ printf("%s:%d: error: free(%p): bad start cookie\n",
+ file, line, ptr);
+ abort();
+ }
+
+ TAILQ_FOREACH(h, &debug_alloc_hdr_list, next) {
+ if (h == hdr)
+ break;
+ }
+
+ if (h == NULL) {
+ printf("%s:%d: error: free(%p): bad ptr\n",
+ file, line, ptr);
+ abort();
+ }
+
+ TAILQ_REMOVE(&debug_alloc_hdr_list, hdr, next);
+ free(hdr);
+}
+
+void *debug_realloc(void *ptr, size_t size, const char *file, unsigned int line)
+{
+ struct debug_alloc_hdr *hdr = (ptr - sizeof(*hdr));
+ struct debug_alloc_hdr *h;
+ size_t new_size = size + sizeof(*hdr) + sizeof(unsigned int);
+ void *ret;
+
+ if (ptr != NULL) {
+ if (hdr->cookie != 0x12345678) {
+ printf("%s:%d: error: realloc(%p): bad start cookie\n",
+ file, line, ptr);
+ abort();
+ }
+
+ TAILQ_FOREACH(h, &debug_alloc_hdr_list, next) {
+ if (h == hdr)
+ break;
+ }
+
+ if (h == NULL) {
+ printf("%s:%d: error: realloc(%p): bad ptr\n",
+ file, line, ptr);
+ abort();
+ }
+
+ TAILQ_REMOVE(&debug_alloc_hdr_list, h, next);
+ hdr = realloc(hdr, new_size);
+ if (hdr == NULL) {
+ TAILQ_INSERT_TAIL(&debug_alloc_hdr_list, h, next);
+ ret = NULL;
+ } else {
+ ret = hdr + 1;
+ }
+ } else {
+ hdr = realloc(NULL, new_size);
+ if (hdr == NULL)
+ ret = NULL;
+ else
+ ret= hdr + 1;
+ }
+
+ if (hdr != NULL) {
+ hdr->file = file;
+ hdr->line = line;
+ hdr->size = size;
+ hdr->cookie = 0x12345678;
+ TAILQ_INSERT_TAIL(&debug_alloc_hdr_list, hdr, next);
+ }
+
+ printf("%s:%d: info: realloc(%p, %zd) -> %p\n",
+ file, line, ptr, size, ret);
+
+ return ret;
+}
+
+void debug_alloc_dump(void)
+{
+ struct debug_alloc_hdr *hdr;
+
+ TAILQ_FOREACH(hdr, &debug_alloc_hdr_list, next) {
+ printf("%s:%d: error: memory leak size=%zd ptr=%p\n",
+ hdr->file, hdr->line, hdr->size, hdr + 1);
+ }
+}
+
/* int ec_test_check_tk_complete_list(const struct ec_tk *tk, */
/* const char *input, ...) */
struct ec_test *test;
int ret = 0;
- // XXX register a new malloc to trac memleaks
+ TAILQ_INIT(&debug_alloc_hdr_list);
+
+ /* register a new malloc to trac memleaks */
+ if (ec_malloc_register(debug_malloc, debug_free, debug_realloc) < 0) {
+ printf("cannot register new malloc\n");
+ return -1;
+ }
TAILQ_FOREACH(test, &test_list, next) {
if (test->test() == 0) {
}
}
+ ec_malloc_unregister();
+ debug_alloc_dump();
+
return ret;
}
if (ec_tk_int_getval(tk, s) != 0)
TEST_ERR();
}
+ ec_parsed_tk_free(p);
p = ec_tk_parse(tk, "10");
s = ec_parsed_tk_to_string(p);
if (ec_tk_int_getval(tk, s) != 10)
TEST_ERR();
}
-
+ ec_parsed_tk_free(p);
ec_tk_free(tk);
tk = ec_tk_int_new(NULL, -1, LLONG_MAX, 16);
if (ec_tk_int_getval(tk, s) != 16)
TEST_ERR();
}
-
+ ec_parsed_tk_free(p);
ec_tk_free(tk);
tk = ec_tk_int_new(NULL, LLONG_MIN, 0, 10);
static void free_priv(struct ec_tk *gen_tk)
{
struct ec_tk_or *tk = (struct ec_tk_or *)gen_tk;
+ unsigned int i;
+ for (i = 0; i < tk->len; i++)
+ ec_tk_free(tk->table[i]);
ec_free(tk->table);
}
tk = (struct ec_tk_or *)ec_tk_new(id, &or_ops, sizeof(*tk));
if (tk == NULL)
- goto fail;
+ return NULL;
tk->table = NULL;
tk->len = 0;
return &tk->gen;
-
-fail:
- ec_free(tk);
- return NULL;
}
struct ec_tk *ec_tk_or_new_list(const char *id, ...)
return &tk->gen;
fail:
- ec_free(tk); // XXX use tk_free? we need to delete all child on error
+ ec_tk_free(&tk->gen); /* will also free children */
va_end(ap);
return NULL;
}
-int ec_tk_or_add(struct ec_tk *tk, struct ec_tk *child)
+int ec_tk_or_add(struct ec_tk *gen_tk, struct ec_tk *child)
{
- struct ec_tk_or *or = (struct ec_tk_or *)tk;
+ struct ec_tk_or *tk = (struct ec_tk_or *)gen_tk;
struct ec_tk **table;
assert(tk != NULL);
assert(child != NULL);
- table = realloc(or->table, (or->len + 1) * sizeof(*or->table));
+ table = ec_realloc(tk->table, (tk->len + 1) * sizeof(*tk->table));
if (table == NULL)
return -1;
- or->table = table;
- table[or->len] = child;
- or->len ++;
+ tk->table = table;
+ table[tk->len] = child;
+ tk->len ++;
return 0;
}
struct ec_tk *ec_tk_or_new(const char *id);
/* list must be terminated with EC_TK_ENDLIST */
+/* all token given in the list will be freed when freeing this one */
struct ec_tk *ec_tk_or_new_list(const char *id, ...);
+/* all token given in the list will be freed when freeing this one */
int ec_tk_or_add(struct ec_tk *tk, struct ec_tk *child);
#endif
// XXX to handle the quote, it will be done in tk_shseq
// it will unquote the string and parse each token separately
-static struct ec_parsed_tk *parse(const struct ec_tk *tk,
+static struct ec_parsed_tk *parse(const struct ec_tk *gen_tk,
const char *str)
{
- struct ec_tk_seq *seq = (struct ec_tk_seq *)tk;
+ struct ec_tk_seq *tk = (struct ec_tk_seq *)gen_tk;
struct ec_parsed_tk *parsed_tk, *child_parsed_tk;
size_t len = 0;
unsigned int i;
- parsed_tk = ec_parsed_tk_new(tk);
+ parsed_tk = ec_parsed_tk_new(gen_tk);
if (parsed_tk == NULL)
return NULL;
- for (i = 0; i < seq->len; i++) {
- child_parsed_tk = ec_tk_parse(seq->table[i], str + len);
+ for (i = 0; i < tk->len; i++) {
+ child_parsed_tk = ec_tk_parse(tk->table[i], str + len);
if (child_parsed_tk == NULL)
goto fail;
return NULL;
}
+static void free_priv(struct ec_tk *gen_tk)
+{
+ struct ec_tk_seq *tk = (struct ec_tk_seq *)gen_tk;
+ unsigned int i;
+
+ for (i = 0; i < tk->len; i++)
+ ec_tk_free(tk->table[i]);
+ ec_free(tk->table);
+}
+
static struct ec_tk_ops seq_ops = {
.parse = parse,
+ .free_priv = free_priv,
};
struct ec_tk *ec_tk_seq_new(const char *id)
tk = (struct ec_tk_seq *)ec_tk_new(id, &seq_ops, sizeof(*tk));
if (tk == NULL)
- goto fail;
+ return NULL;
tk->table = NULL;
tk->len = 0;
return &tk->gen;
-
-fail:
- ec_free(tk);
- return NULL;
}
struct ec_tk *ec_tk_seq_new_list(const char *id, ...)
return &tk->gen;
fail:
- ec_free(tk); // XXX use tk_free? we need to delete all child on error
+ ec_tk_free(&tk->gen); /* will also free children */
va_end(ap);
return NULL;
}
-int ec_tk_seq_add(struct ec_tk *tk, struct ec_tk *child)
+int ec_tk_seq_add(struct ec_tk *gen_tk, struct ec_tk *child)
{
- struct ec_tk_seq *seq = (struct ec_tk_seq *)tk;
+ struct ec_tk_seq *tk = (struct ec_tk_seq *)gen_tk;
struct ec_tk **table;
assert(tk != NULL);
assert(child != NULL);
- table = realloc(seq->table, seq->len + 1);
+ table = ec_realloc(tk->table, tk->len + 1);
if (table == NULL)
return -1;
- seq->table = table;
- table[seq->len] = child;
- seq->len ++;
+ tk->table = table;
+ table[tk->len] = child;
+ tk->len ++;
return 0;
}