diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 55051b8..80e9304 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -290,7 +290,8 @@ struct event_desc { #define OPT_AUTH_LOG 76 #define OPT_LEASEQUERY 77 #define OPT_LOG_ONLY_FAILED 78 -#define OPT_LAST 79 +#define OPT_LOG_MALLOC 79 +#define OPT_LAST 80 #define OPTION_BITS (sizeof(unsigned int)*8) #define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) ) @@ -1495,8 +1496,12 @@ unsigned char *do_rfc1035_name(unsigned char *p, char *sval, char *limit); void *safe_malloc(size_t size); void safe_strncpy(char *dest, const char *src, size_t size); void safe_pipe(int *fd, int read_noblock); -void *whine_malloc(size_t size); -void *whine_realloc(void *ptr, size_t size); +#define whine_malloc(x) whine_malloc_real(__func__, __LINE__, (x)) +#define whine_realloc(x, y) whine_realloc_real(__func__, __LINE__, (x), (y)) +#define free(x) free_real(__func__, __LINE__, (x)) +void free_real(const char *func, unsigned int line, void *ptr); +void *whine_malloc_real(const char *func, unsigned int line, size_t size); +void *whine_realloc_real(const char *func, unsigned int line, void *ptr, size_t size); int sa_len(union mysockaddr *addr); int sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2); int sockaddr_isnull(const union mysockaddr *s); diff --git a/src/option.c b/src/option.c index 67f3a45..550a50f 100644 --- a/src/option.c +++ b/src/option.c @@ -197,6 +197,7 @@ struct myoption { #define LOPT_DO_ENCODE 388 #define LOPT_LEASEQUERY 389 #define LOPT_SPLIT_RELAY 390 +#define LOPT_LOG_MALLOC 391 #ifdef HAVE_GETOPT_LONG static const struct option opts[] = @@ -398,6 +399,7 @@ static const struct myoption opts[] = { "no-ident", 0, 0, LOPT_NO_IDENT }, { "max-tcp-connections", 1, 0, LOPT_MAX_PROCS }, { "leasequery", 2, 0, LOPT_LEASEQUERY }, + { "log-malloc", 0, 0, LOPT_LOG_MALLOC }, { NULL, 0, 0, 0 } }; @@ -606,6 +608,7 @@ static struct { { LOPT_NO_IDENT, OPT_NO_IDENT, NULL, gettext_noop("Do not add CHAOS TXT records."), NULL }, { LOPT_CACHE_RR, ARG_DUP, "", gettext_noop("Cache this DNS resource record type."), NULL }, { LOPT_MAX_PROCS, ARG_ONE, "", gettext_noop("Maximum number of concurrent tcp connections."), NULL }, + { LOPT_LOG_MALLOC, OPT_LOG_MALLOC, NULL, gettext_noop("Log memory allocation for debugging."), NULL }, { 0, 0, NULL, NULL, NULL } }; diff --git a/src/util.c b/src/util.c index e4d74e6..40214b3 100644 --- a/src/util.c +++ b/src/util.c @@ -341,26 +341,6 @@ void safe_pipe(int *fd, int read_noblock) die(_("cannot create pipe: %s"), NULL, EC_MISC); } -void *whine_malloc(size_t size) -{ - void *ret = calloc(1, size); - - if (!ret) - my_syslog(LOG_ERR, _("failed to allocate %d bytes"), (int) size); - - return ret; -} - -void *whine_realloc(void *ptr, size_t size) -{ - void *ret = realloc(ptr, size); - - if (!ret) - my_syslog(LOG_ERR, _("failed to reallocate %d bytes"), (int) size); - - return ret; -} - int sockaddr_isequal(const union mysockaddr *s1, const union mysockaddr *s2) { if (s1->sa.sa_family == s2->sa.sa_family) @@ -949,3 +929,39 @@ int kernel_version(void) return version * 256 + (split ? atoi(split) : 0); } #endif + +#define hash_ptr(x) (((unsigned int)(((char *)(x)) - ((char *)NULL))) & 0xffffff) + +void *whine_malloc_real(const char *func, unsigned int line, size_t size) +{ + void *ret = calloc(1, size); + + if (!ret) + my_syslog(LOG_ERR, _("failed to allocate %d bytes"), (int) size); + else if (option_bool(OPT_LOG_MALLOC)) + my_syslog(LOG_INFO, _("malloc: %s:%u %zu bytes at %x"), func, line, size, hash_ptr(ret)); + + return ret; +} + +void *whine_realloc_real(const char *func, unsigned int line, void *ptr, size_t size) +{ + unsigned int old = hash_ptr(ptr); + void *ret = realloc(ptr, size); + + if (!ret) + my_syslog(LOG_ERR, _("failed to reallocate %d bytes"), (int) size); + else if (option_bool(OPT_LOG_MALLOC)) + my_syslog(LOG_INFO, _("realloc: %s:%u %zu bytes from %x to %x"), func, line, size, old, hash_ptr(ret)); + + return ret; +} + +void free_real(const char *func, unsigned int line, void *ptr) +{ + if (option_bool(OPT_LOG_MALLOC)) + my_syslog(LOG_INFO, _("free: %s:%u block at %x"), func, line, hash_ptr(ptr)); + +#undef free + free(ptr); +}