diff --git a/src/utils/eloop.c b/src/utils/eloop.c index 3265b5e2a..fa33d4c63 100644 --- a/src/utils/eloop.c +++ b/src/utils/eloop.c @@ -25,6 +25,8 @@ struct eloop_sock { void *eloop_data; void *user_data; eloop_sock_handler handler; + WPA_TRACE_REF(eloop); + WPA_TRACE_REF(user); WPA_TRACE_INFO }; @@ -34,6 +36,8 @@ struct eloop_timeout { void *eloop_data; void *user_data; eloop_timeout_handler handler; + WPA_TRACE_REF(eloop); + WPA_TRACE_REF(user); WPA_TRACE_INFO }; @@ -72,11 +76,45 @@ static struct eloop_data eloop; #ifdef WPA_TRACE + static void eloop_sigsegv_handler(int sig) { wpa_trace_show("eloop SIGSEGV"); abort(); } + +static void eloop_trace_sock_add_ref(struct eloop_sock_table *table) +{ + int i; + if (table == NULL || table->table == NULL) + return; + for (i = 0; i < table->count; i++) { + wpa_trace_add_ref(&table->table[i], eloop, + table->table[i].eloop_data); + wpa_trace_add_ref(&table->table[i], user, + table->table[i].user_data); + } +} + + +static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table) +{ + int i; + if (table == NULL || table->table == NULL) + return; + for (i = 0; i < table->count; i++) { + wpa_trace_remove_ref(&table->table[i], eloop, + table->table[i].eloop_data); + wpa_trace_remove_ref(&table->table[i], user, + table->table[i].user_data); + } +} + +#else /* WPA_TRACE */ + +#define eloop_trace_sock_add_ref(table) do { } while (0) +#define eloop_trace_sock_remove_ref(table) do { } while (0) + #endif /* WPA_TRACE */ @@ -100,6 +138,7 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table, if (table == NULL) return -1; + eloop_trace_sock_remove_ref(table); tmp = (struct eloop_sock *) os_realloc(table->table, (table->count + 1) * sizeof(struct eloop_sock)); @@ -116,6 +155,7 @@ static int eloop_sock_table_add_sock(struct eloop_sock_table *table, if (sock > eloop.max_sock) eloop.max_sock = sock; table->changed = 1; + eloop_trace_sock_add_ref(table); return 0; } @@ -135,6 +175,7 @@ static void eloop_sock_table_remove_sock(struct eloop_sock_table *table, } if (i == table->count) return; + eloop_trace_sock_remove_ref(table); if (i != table->count - 1) { os_memmove(&table->table[i], &table->table[i + 1], (table->count - i - 1) * @@ -142,6 +183,7 @@ static void eloop_sock_table_remove_sock(struct eloop_sock_table *table, } table->count--; table->changed = 1; + eloop_trace_sock_add_ref(table); } @@ -272,6 +314,8 @@ int eloop_register_timeout(unsigned int secs, unsigned int usecs, timeout->eloop_data = eloop_data; timeout->user_data = user_data; timeout->handler = handler; + wpa_trace_add_ref(timeout, eloop, eloop_data); + wpa_trace_add_ref(timeout, user, user_data); wpa_trace_record(timeout); /* Maintain timeouts in order of increasing time */ @@ -287,6 +331,14 @@ int eloop_register_timeout(unsigned int secs, unsigned int usecs, } +static void eloop_remove_timeout(struct eloop_timeout *timeout) +{ + wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data); + wpa_trace_remove_ref(timeout, user, timeout->user_data); + os_free(timeout); +} + + int eloop_cancel_timeout(eloop_timeout_handler handler, void *eloop_data, void *user_data) { @@ -301,7 +353,7 @@ int eloop_cancel_timeout(eloop_timeout_handler handler, (timeout->user_data == user_data || user_data == ELOOP_ALL_CTX)) { dl_list_del(&timeout->list); - os_free(timeout); + eloop_remove_timeout(timeout); removed++; } } @@ -480,7 +532,7 @@ void eloop_run(void) dl_list_del(&timeout->list); timeout->handler(timeout->eloop_data, timeout->user_data); - os_free(timeout); + eloop_remove_timeout(timeout); } } @@ -526,7 +578,8 @@ void eloop_destroy(void) sec, usec, timeout->eloop_data, timeout->user_data, timeout->handler); wpa_trace_dump("eloop timeout", timeout); - os_free(timeout); + dl_list_del(&timeout->list); + eloop_remove_timeout(timeout); } eloop_sock_table_destroy(&eloop.readers); eloop_sock_table_destroy(&eloop.writers); diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c index 6748e752f..cb23f7207 100644 --- a/src/utils/os_unix.c +++ b/src/utils/os_unix.c @@ -407,6 +407,7 @@ void os_free(void *ptr) dl_list_del(&a->list); a->magic = FREED_MAGIC; + wpa_trace_check_ref(ptr); free(a); } diff --git a/src/utils/trace.c b/src/utils/trace.c index cf1001063..35cb8bd2a 100644 --- a/src/utils/trace.c +++ b/src/utils/trace.c @@ -19,6 +19,9 @@ #ifdef WPA_TRACE +static struct dl_list active_references = +{ &active_references, &active_references }; + #ifdef WPA_TRACE_BFD #include #include @@ -255,4 +258,27 @@ void wpa_trace_show(const char *title) wpa_trace_dump(title, &info); } + +void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr) +{ + if (addr == NULL) + return; + ref->addr = addr; + wpa_trace_record(ref); + dl_list_add(&active_references, &ref->list); +} + + +void wpa_trace_check_ref(const void *addr) +{ + struct wpa_trace_ref *ref; + dl_list_for_each(ref, &active_references, struct wpa_trace_ref, list) { + if (addr != ref->addr) + continue; + wpa_trace_show("Freeing referenced memory"); + wpa_trace_dump("Reference registration", ref); + abort(); + } +} + #endif /* WPA_TRACE */ diff --git a/src/utils/trace.h b/src/utils/trace.h index 8074d25d3..009b6e318 100644 --- a/src/utils/trace.h +++ b/src/utils/trace.h @@ -20,20 +20,43 @@ #ifdef WPA_TRACE #include +#include "list.h" + #define WPA_TRACE_INFO void *btrace[WPA_TRACE_LEN]; int btrace_num; + +struct wpa_trace_ref { + struct dl_list list; + const void *addr; + WPA_TRACE_INFO +}; +#define WPA_TRACE_REF(name) struct wpa_trace_ref wpa_trace_ref_##name + #define wpa_trace_dump(title, ptr) \ wpa_trace_dump_func((title), (ptr)->btrace, (ptr)->btrace_num) void wpa_trace_dump_func(const char *title, void **btrace, int btrace_num); #define wpa_trace_record(ptr) \ (ptr)->btrace_num = backtrace((ptr)->btrace, WPA_TRACE_LEN) void wpa_trace_show(const char *title); +#define wpa_trace_add_ref(ptr, name, addr) \ + wpa_trace_add_ref_func(&(ptr)->wpa_trace_ref_##name, (addr)) +void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr); +#define wpa_trace_remove_ref(ptr, name, addr) \ + do { \ + if ((addr)) \ + dl_list_del(&(ptr)->wpa_trace_ref_##name.list); \ + } while (0) +void wpa_trace_check_ref(const void *addr); #else /* WPA_TRACE */ #define WPA_TRACE_INFO +#define WPA_TRACE_REF(n) #define wpa_trace_dump(title, ptr) do { } while (0) #define wpa_trace_record(ptr) do { } while (0) #define wpa_trace_show(title) do { } while (0) +#define wpa_trace_add_ref(ptr, name, addr) do { } while (0) +#define wpa_trace_remove_ref(ptr, name, addr) do { } while (0) +#define wpa_trace_check_ref(addr) do { } while (0) #endif /* WPA_TRACE */