NRF7002 getaddrindo memory leak

Hello,

I am continuing to build my prototype on NRF7002 DK, and noticed several memory leaks.

The first one surfaced when fetching wifi status in via NET_REQUEST_WIFI_IFACE_STATUS. It was already fixed in zephyr/src/supp_api.c, but unfortunately never made it to 2.4.1. I could cherry pick the fix, but decided to move to the HEAD of NRF Connect SDK repo, which functionally works just great. But, there seem to be another memory leak in DNS resolver (which most probably has been there for some time). In particular, calling getaddrinfo (followed by freeaddrinfo) multiple times results in several out of memory errors and eventually system hangs.

I've honestly failed to figure out where the actual leak happens, but I was able to update the STA sample with a simple repro (below) - just run it for around 40 seconds, and you should see errors from the wpa supplicant on insufficient memory (wpa_supp: ctrl_iface: reply malloc of 1024 failed).

Is this a known issue? Is it even a memory leak? Can you provide hints how to fix it?

Thanks,
-Vigen

Sample code:

static void resolve_dns() {
  while (1) {
    struct addrinfo* addr_info = NULL;
    struct addrinfo hints = {.ai_family = AF_UNSPEC,
                             .ai_socktype = SOCK_STREAM};
    int err = getaddrinfo("www.google.com", NULL, &hints, &addr_info);
    if (!err) {
      for (; addr_info; addr_info = addr_info->ai_next) {
        if (addr_info->ai_family != AF_INET &&
            addr_info->ai_family != AF_INET6) {
          continue;
        }
        char ip_addr[NET_IPV6_ADDR_LEN + 1];
        if (inet_ntop(addr_info->ai_family, &addr_info->ai_addr, ip_addr,
                      sizeof(ip_addr))) {
          LOG_DBG("Successfully resolved IP address: ip=%s", ip_addr);
          continue;
        }
      }
      freeaddrinfo(addr_info);
    }
    k_sleep(K_MSEC(50));
  }
}

int main() {
// ...

		if (context.connected) {
			// k_sleep(K_FOREVER);
			resolve_dns();
		} 
// ...
}

Parents
  • Hi again

    We were able to reproduce this issue and have found the root cause. There's a bug in your implementation where the address passed to freeaddrinfo will always be NULL, as it is after the traversal of the linked list, and hence the memory allocated for linked list is never freed, so every iteration of the while loop leaks 2 * sizeof(struct addrinfo) bytes.

    With the below fix, the memory leak is not seen anymore on our end (verified by dumping malloc_stats() in the loop).

    diff --git a/samples/wifi/sta/src/main.c b/samples/wifi/sta/src/main.c
    index 30e41c8c8b8..33599f76ec0 100644
    --- a/samples/wifi/sta/src/main.c
    +++ b/samples/wifi/sta/src/main.c
    @@ -96,11 +96,12 @@ void toggle_led(void)
    
     static void resolve_dns() {
       while (1) {
    -       struct addrinfo* addr_info = NULL;
    +       struct addrinfo* addr_info = NULL, *tmp_addr_info = NULL;
            struct addrinfo hints = {.ai_family = AF_UNSPEC,
                                                             .ai_socktype = SOCK_STREAM};
            int err = getaddrinfo("www.google.com", NULL, &hints, &addr_info);
            if (!err) {
    +         tmp_addr_info = addr_info;
              for (; addr_info; addr_info = addr_info->ai_next) {
                    if (addr_info->ai_family != AF_INET &&
                            addr_info->ai_family != AF_INET6) {
    @@ -113,7 +114,7 @@ static void resolve_dns() {
                      continue;
                    }
              }
    -         freeaddrinfo(addr_info);
    +         freeaddrinfo(tmp_addr_info);
            }
            k_sleep(K_MSEC(50));
       }

    Best regards,

    Simon

Reply
  • Hi again

    We were able to reproduce this issue and have found the root cause. There's a bug in your implementation where the address passed to freeaddrinfo will always be NULL, as it is after the traversal of the linked list, and hence the memory allocated for linked list is never freed, so every iteration of the while loop leaks 2 * sizeof(struct addrinfo) bytes.

    With the below fix, the memory leak is not seen anymore on our end (verified by dumping malloc_stats() in the loop).

    diff --git a/samples/wifi/sta/src/main.c b/samples/wifi/sta/src/main.c
    index 30e41c8c8b8..33599f76ec0 100644
    --- a/samples/wifi/sta/src/main.c
    +++ b/samples/wifi/sta/src/main.c
    @@ -96,11 +96,12 @@ void toggle_led(void)
    
     static void resolve_dns() {
       while (1) {
    -       struct addrinfo* addr_info = NULL;
    +       struct addrinfo* addr_info = NULL, *tmp_addr_info = NULL;
            struct addrinfo hints = {.ai_family = AF_UNSPEC,
                                                             .ai_socktype = SOCK_STREAM};
            int err = getaddrinfo("www.google.com", NULL, &hints, &addr_info);
            if (!err) {
    +         tmp_addr_info = addr_info;
              for (; addr_info; addr_info = addr_info->ai_next) {
                    if (addr_info->ai_family != AF_INET &&
                            addr_info->ai_family != AF_INET6) {
    @@ -113,7 +114,7 @@ static void resolve_dns() {
                      continue;
                    }
              }
    -         freeaddrinfo(addr_info);
    +         freeaddrinfo(tmp_addr_info);
            }
            k_sleep(K_MSEC(50));
       }

    Best regards,

    Simon

Children
Related