Add memory allocation analyzer to verify OS wrapper use
WPA_TRACE=y builds will now verify that memory allocation in done consistently using os_{zalloc,malloc,realloc,strdup,free} (i.e., no mixing of os_* functions and unwrapper functions). In addition, some common memory allocation issues (double-free, memory leaks, etc.) are detected automatically.
This commit is contained in:
parent
80d77c31ff
commit
fb4baa688b
5 changed files with 174 additions and 23 deletions
|
@ -720,6 +720,10 @@ hostapd: $(BCHECK) $(OBJS)
|
||||||
$(CC) $(LDFLAGS) -o hostapd $(OBJS) $(LIBS)
|
$(CC) $(LDFLAGS) -o hostapd $(OBJS) $(LIBS)
|
||||||
|
|
||||||
OBJS_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o
|
OBJS_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o
|
||||||
|
ifdef CONFIG_WPA_TRACE
|
||||||
|
OBJS_c += ../src/utils/trace.o
|
||||||
|
OBJS_c += ../src/utils/wpa_debug.o
|
||||||
|
endif
|
||||||
hostapd_cli: $(OBJS_c)
|
hostapd_cli: $(OBJS_c)
|
||||||
$(CC) $(LDFLAGS) -o hostapd_cli $(OBJS_c)
|
$(CC) $(LDFLAGS) -o hostapd_cli $(OBJS_c)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* wpa_supplicant/hostapd / OS specific functions
|
* OS specific functions
|
||||||
* Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
|
* Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
@ -379,6 +379,12 @@ int os_snprintf(char *str, size_t size, const char *format, ...);
|
||||||
|
|
||||||
#else /* OS_NO_C_LIB_DEFINES */
|
#else /* OS_NO_C_LIB_DEFINES */
|
||||||
|
|
||||||
|
#ifdef WPA_TRACE
|
||||||
|
void * os_malloc(size_t size);
|
||||||
|
void * os_realloc(void *ptr, size_t size);
|
||||||
|
void os_free(void *ptr);
|
||||||
|
char * os_strdup(const char *s);
|
||||||
|
#else /* WPA_TRACE */
|
||||||
#ifndef os_malloc
|
#ifndef os_malloc
|
||||||
#define os_malloc(s) malloc((s))
|
#define os_malloc(s) malloc((s))
|
||||||
#endif
|
#endif
|
||||||
|
@ -388,6 +394,14 @@ int os_snprintf(char *str, size_t size, const char *format, ...);
|
||||||
#ifndef os_free
|
#ifndef os_free
|
||||||
#define os_free(p) free((p))
|
#define os_free(p) free((p))
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef os_strdup
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define os_strdup(s) _strdup(s)
|
||||||
|
#else
|
||||||
|
#define os_strdup(s) strdup(s)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif /* WPA_TRACE */
|
||||||
|
|
||||||
#ifndef os_memcpy
|
#ifndef os_memcpy
|
||||||
#define os_memcpy(d, s, n) memcpy((d), (s), (n))
|
#define os_memcpy(d, s, n) memcpy((d), (s), (n))
|
||||||
|
@ -402,13 +416,6 @@ int os_snprintf(char *str, size_t size, const char *format, ...);
|
||||||
#define os_memcmp(s1, s2, n) memcmp((s1), (s2), (n))
|
#define os_memcmp(s1, s2, n) memcmp((s1), (s2), (n))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef os_strdup
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#define os_strdup(s) _strdup(s)
|
|
||||||
#else
|
|
||||||
#define os_strdup(s) strdup(s)
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#ifndef os_strlen
|
#ifndef os_strlen
|
||||||
#define os_strlen(s) strlen(s)
|
#define os_strlen(s) strlen(s)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* wpa_supplicant/hostapd / OS specific functions for UNIX/POSIX systems
|
* OS specific functions for UNIX/POSIX systems
|
||||||
* Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
|
* Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
@ -16,6 +16,28 @@
|
||||||
|
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
|
|
||||||
|
#ifdef WPA_TRACE
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "list.h"
|
||||||
|
#include "wpa_debug.h"
|
||||||
|
#include "trace.h"
|
||||||
|
|
||||||
|
static struct dl_list alloc_list;
|
||||||
|
|
||||||
|
#define ALLOC_MAGIC 0xa84ef1b2
|
||||||
|
#define FREED_MAGIC 0x67fd487a
|
||||||
|
|
||||||
|
struct os_alloc_trace {
|
||||||
|
unsigned int magic;
|
||||||
|
struct dl_list list;
|
||||||
|
size_t len;
|
||||||
|
WPA_TRACE_INFO
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* WPA_TRACE */
|
||||||
|
|
||||||
|
|
||||||
void os_sleep(os_time_t sec, os_time_t usec)
|
void os_sleep(os_time_t sec, os_time_t usec)
|
||||||
{
|
{
|
||||||
if (sec)
|
if (sec)
|
||||||
|
@ -172,16 +194,16 @@ char * os_rel2abs_path(const char *rel_path)
|
||||||
int last_errno;
|
int last_errno;
|
||||||
|
|
||||||
if (rel_path[0] == '/')
|
if (rel_path[0] == '/')
|
||||||
return strdup(rel_path);
|
return os_strdup(rel_path);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
buf = malloc(len);
|
buf = os_malloc(len);
|
||||||
if (buf == NULL)
|
if (buf == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
cwd = getcwd(buf, len);
|
cwd = getcwd(buf, len);
|
||||||
if (cwd == NULL) {
|
if (cwd == NULL) {
|
||||||
last_errno = errno;
|
last_errno = errno;
|
||||||
free(buf);
|
os_free(buf);
|
||||||
if (last_errno != ERANGE)
|
if (last_errno != ERANGE)
|
||||||
return NULL;
|
return NULL;
|
||||||
len *= 2;
|
len *= 2;
|
||||||
|
@ -193,29 +215,51 @@ char * os_rel2abs_path(const char *rel_path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cwd_len = strlen(cwd);
|
cwd_len = os_strlen(cwd);
|
||||||
rel_len = strlen(rel_path);
|
rel_len = os_strlen(rel_path);
|
||||||
ret_len = cwd_len + 1 + rel_len + 1;
|
ret_len = cwd_len + 1 + rel_len + 1;
|
||||||
ret = malloc(ret_len);
|
ret = os_malloc(ret_len);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
memcpy(ret, cwd, cwd_len);
|
os_memcpy(ret, cwd, cwd_len);
|
||||||
ret[cwd_len] = '/';
|
ret[cwd_len] = '/';
|
||||||
memcpy(ret + cwd_len + 1, rel_path, rel_len);
|
os_memcpy(ret + cwd_len + 1, rel_path, rel_len);
|
||||||
ret[ret_len - 1] = '\0';
|
ret[ret_len - 1] = '\0';
|
||||||
}
|
}
|
||||||
free(buf);
|
os_free(buf);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int os_program_init(void)
|
int os_program_init(void)
|
||||||
{
|
{
|
||||||
|
#ifdef WPA_TRACE
|
||||||
|
dl_list_init(&alloc_list);
|
||||||
|
#endif /* WPA_TRACE */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void os_program_deinit(void)
|
void os_program_deinit(void)
|
||||||
{
|
{
|
||||||
|
#ifdef WPA_TRACE
|
||||||
|
struct os_alloc_trace *a;
|
||||||
|
unsigned long total = 0;
|
||||||
|
dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) {
|
||||||
|
total += a->len;
|
||||||
|
if (a->magic != ALLOC_MAGIC) {
|
||||||
|
wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x "
|
||||||
|
"len %lu",
|
||||||
|
a, a->magic, (unsigned long) a->len);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu",
|
||||||
|
a, (unsigned long) a->len);
|
||||||
|
wpa_trace_dump("memleak", a);
|
||||||
|
}
|
||||||
|
if (total)
|
||||||
|
wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes",
|
||||||
|
(unsigned long) total);
|
||||||
|
#endif /* WPA_TRACE */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -250,7 +294,7 @@ char * os_readfile(const char *name, size_t *len)
|
||||||
*len = ftell(f);
|
*len = ftell(f);
|
||||||
fseek(f, 0, SEEK_SET);
|
fseek(f, 0, SEEK_SET);
|
||||||
|
|
||||||
buf = malloc(*len);
|
buf = os_malloc(*len);
|
||||||
if (buf == NULL) {
|
if (buf == NULL) {
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -258,7 +302,7 @@ char * os_readfile(const char *name, size_t *len)
|
||||||
|
|
||||||
if (fread(buf, 1, *len, f) != *len) {
|
if (fread(buf, 1, *len, f) != *len) {
|
||||||
fclose(f);
|
fclose(f);
|
||||||
free(buf);
|
os_free(buf);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,10 +312,12 @@ char * os_readfile(const char *name, size_t *len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef WPA_TRACE
|
||||||
void * os_zalloc(size_t size)
|
void * os_zalloc(size_t size)
|
||||||
{
|
{
|
||||||
return calloc(1, size);
|
return calloc(1, size);
|
||||||
}
|
}
|
||||||
|
#endif /* WPA_TRACE */
|
||||||
|
|
||||||
|
|
||||||
size_t os_strlcpy(char *dest, const char *src, size_t siz)
|
size_t os_strlcpy(char *dest, const char *src, size_t siz)
|
||||||
|
@ -297,3 +343,94 @@ size_t os_strlcpy(char *dest, const char *src, size_t siz)
|
||||||
|
|
||||||
return s - src - 1;
|
return s - src - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef WPA_TRACE
|
||||||
|
|
||||||
|
void * os_malloc(size_t size)
|
||||||
|
{
|
||||||
|
struct os_alloc_trace *a;
|
||||||
|
a = malloc(sizeof(*a) + size);
|
||||||
|
if (a == NULL)
|
||||||
|
return NULL;
|
||||||
|
a->magic = ALLOC_MAGIC;
|
||||||
|
dl_list_add(&alloc_list, &a->list);
|
||||||
|
a->len = size;
|
||||||
|
wpa_trace_record(a);
|
||||||
|
return a + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void * os_realloc(void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
struct os_alloc_trace *a;
|
||||||
|
size_t copy_len;
|
||||||
|
void *n;
|
||||||
|
|
||||||
|
if (ptr == NULL)
|
||||||
|
return os_malloc(size);
|
||||||
|
|
||||||
|
a = ptr - sizeof(*a);
|
||||||
|
if (a->magic != ALLOC_MAGIC) {
|
||||||
|
wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s",
|
||||||
|
a, a->magic,
|
||||||
|
a->magic == FREED_MAGIC ? " (already freed)" : "");
|
||||||
|
wpa_trace_show("Invalid os_realloc() call");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
n = os_malloc(size);
|
||||||
|
if (n == NULL)
|
||||||
|
return NULL;
|
||||||
|
copy_len = a->len;
|
||||||
|
if (copy_len > size)
|
||||||
|
copy_len = size;
|
||||||
|
os_memcpy(n, a + 1, copy_len);
|
||||||
|
os_free(ptr);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void os_free(void *ptr)
|
||||||
|
{
|
||||||
|
struct os_alloc_trace *a;
|
||||||
|
|
||||||
|
if (ptr == NULL)
|
||||||
|
return;
|
||||||
|
a = ptr - sizeof(*a);
|
||||||
|
if (a->magic != ALLOC_MAGIC) {
|
||||||
|
wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s",
|
||||||
|
a, a->magic,
|
||||||
|
a->magic == FREED_MAGIC ? " (already freed)" : "");
|
||||||
|
wpa_trace_show("Invalid os_free() call");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
dl_list_del(&a->list);
|
||||||
|
a->magic = FREED_MAGIC;
|
||||||
|
|
||||||
|
free(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void * os_zalloc(size_t size)
|
||||||
|
{
|
||||||
|
void *ptr = os_malloc(size);
|
||||||
|
if (ptr)
|
||||||
|
os_memset(ptr, 0, size);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
char * os_strdup(const char *s)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
char *d;
|
||||||
|
len = os_strlen(s);
|
||||||
|
d = os_malloc(len + 1);
|
||||||
|
if (d == NULL)
|
||||||
|
return NULL;
|
||||||
|
os_memcpy(d, s, len);
|
||||||
|
d[len] = '\0';
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* WPA_TRACE */
|
||||||
|
|
|
@ -29,7 +29,7 @@ void wpa_trace_dump_func(const char *title, void **btrace, int btrace_num)
|
||||||
for (i = 0; i < btrace_num; i++)
|
for (i = 0; i < btrace_num; i++)
|
||||||
wpa_printf(MSG_INFO, "[%d]: %p: %s",
|
wpa_printf(MSG_INFO, "[%d]: %p: %s",
|
||||||
i, btrace[i], sym ? sym[i] : "");
|
i, btrace[i], sym ? sym[i] : "");
|
||||||
os_free(sym);
|
free(sym);
|
||||||
wpa_printf(MSG_INFO, "WPA_TRACE: %s - END", title);
|
wpa_printf(MSG_INFO, "WPA_TRACE: %s - END", title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,9 @@ OBJS_c += ../src/utils/os_$(CONFIG_OS).o
|
||||||
ifdef CONFIG_WPA_TRACE
|
ifdef CONFIG_WPA_TRACE
|
||||||
CFLAGS += -DWPA_TRACE
|
CFLAGS += -DWPA_TRACE
|
||||||
OBJS += ../src/utils/trace.o
|
OBJS += ../src/utils/trace.o
|
||||||
|
OBJS_p += ../src/utils/trace.o
|
||||||
|
OBJS_c += ../src/utils/trace.o
|
||||||
|
OBJS_c += ../src/utils/wpa_debug.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifndef CONFIG_ELOOP
|
ifndef CONFIG_ELOOP
|
||||||
|
|
Loading…
Reference in a new issue