]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
trace: Add active reference tracking
authorJouni Malinen <j@w1.fi>
Mon, 21 Dec 2009 23:11:15 +0000 (01:11 +0200)
committerJouni Malinen <j@w1.fi>
Mon, 21 Dec 2009 23:11:15 +0000 (01:11 +0200)
This WPA_TRACE=y additions allows components to register active references
to memory that has been provided to them as a pointer. If such an actively
referenced memory area is freed, tracer will report this as an error and
backtraces of both the invalid free and the location where this pointer
was marked referenced are shown.

src/utils/eloop.c
src/utils/os_unix.c
src/utils/trace.c
src/utils/trace.h

index 3265b5e2a9b0a972663d5823ca9088b728c98feb..fa33d4c63d3448e4fc130d1dbaa927404e12a91b 100644 (file)
@@ -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);
index 6748e752fa50e6ccb016ddf7c465f7aa58f65dfe..cb23f72074c2af639569ed8bfb82939eac49a63d 100644 (file)
@@ -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);
 }
 
index cf10010638b73fef5917c17a51c292ec889cd957..35cb8bd2a5d014334393c1d039dca8e4e9b6b260 100644 (file)
@@ -19,6 +19,9 @@
 
 #ifdef WPA_TRACE
 
+static struct dl_list active_references =
+{ &active_references, &active_references };
+
 #ifdef WPA_TRACE_BFD
 #include <bfd.h>
 #include <demangle.h>
@@ -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 */
index 8074d25d3bd4d6a66a52601b1440c0794948eed7..009b6e3184c7990c7ac8ed29f3d322a193d19647 100644 (file)
 #ifdef WPA_TRACE
 #include <execinfo.h>
 
+#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 */