blob: a89babf927dbeff07259c151ec5b445ca7c82ab5 [file] [log] [blame]
/*
* Example memory allocator with machine parseable logging.
*
* Also sizes for reallocs and frees are logged so that the memory
* behavior can be essentially replayed to accurately determine e.g.
* optimal pool sizes for a pooled allocator.
*
* Allocation structure:
*
* [ alloc_hdr | user area ]
*
* ^ ^
* | `--- pointer returned to Duktape
* `--- underlying malloc ptr
*/
#include "duktape.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#define ALLOC_LOG_FILE "/tmp/duk-alloc-log.txt"
typedef struct {
/* The double value in the union is there to ensure alignment is
* good for IEEE doubles too. In many 32-bit environments 4 bytes
* would be sufficiently aligned and the double value is unnecessary.
*/
union {
size_t sz;
double d;
} u;
} alloc_hdr;
static FILE *log_file = NULL;
static void write_log(const char *fmt, ...) {
va_list ap;
if (!log_file) {
log_file = fopen(ALLOC_LOG_FILE, "wb");
if (!log_file) {
return;
}
}
va_start(ap, fmt);
vfprintf(log_file, fmt, ap);
va_end(ap);
}
void *duk_alloc_logging(void *udata, duk_size_t size) {
alloc_hdr *hdr;
void *ret;
(void) udata; /* Suppress warning. */
if (size == 0) {
write_log("A NULL %ld\n", (long) size);
return NULL;
}
hdr = (alloc_hdr *) malloc(size + sizeof(alloc_hdr));
if (!hdr) {
write_log("A FAIL %ld\n", (long) size);
return NULL;
}
hdr->u.sz = size;
ret = (void *) (hdr + 1);
write_log("A %p %ld\n", ret, (long) size);
return ret;
}
void *duk_realloc_logging(void *udata, void *ptr, duk_size_t size) {
alloc_hdr *hdr;
size_t old_size;
void *t;
void *ret;
(void) udata; /* Suppress warning. */
/* Handle the ptr-NULL vs. size-zero cases explicitly to minimize
* platform assumptions. You can get away with much less in specific
* well-behaving environments.
*/
if (ptr) {
hdr = (alloc_hdr *) (void *) ((unsigned char *) ptr - sizeof(alloc_hdr));
old_size = hdr->u.sz;
if (size == 0) {
write_log("R %p %ld NULL 0\n", ptr, (long) old_size);
free((void *) hdr);
return NULL;
} else {
t = realloc((void *) hdr, size + sizeof(alloc_hdr));
if (!t) {
write_log("R %p %ld FAIL %ld\n", ptr, (long) old_size, (long) size);
return NULL;
}
hdr = (alloc_hdr *) t;
hdr->u.sz = size;
ret = (void *) (hdr + 1);
write_log("R %p %ld %p %ld\n", ptr, (long) old_size, ret, (long) size);
return ret;
}
} else {
if (size == 0) {
write_log("R NULL 0 NULL 0\n");
return NULL;
} else {
hdr = (alloc_hdr *) malloc(size + sizeof(alloc_hdr));
if (!hdr) {
write_log("R NULL 0 FAIL %ld\n", (long) size);
return NULL;
}
hdr->u.sz = size;
ret = (void *) (hdr + 1);
write_log("R NULL 0 %p %ld\n", ret, (long) size);
return ret;
}
}
}
void duk_free_logging(void *udata, void *ptr) {
alloc_hdr *hdr;
(void) udata; /* Suppress warning. */
if (!ptr) {
write_log("F NULL 0\n");
return;
}
hdr = (alloc_hdr *) (void *) ((unsigned char *) ptr - sizeof(alloc_hdr));
write_log("F %p %ld\n", ptr, (long) hdr->u.sz);
free((void *) hdr);
}