From: Tomas Gonzalez Date: Mon, 1 Nov 2021 17:01:06 +0000 (-0700) Subject: evutil: Fix evutil_freeaddrinfo X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9a38bc5f73823ac72d6c6b74de7b3ac592a8c7f2;p=libevent evutil: Fix evutil_freeaddrinfo During testing on win32, util/getaddrinfo failed with NULL hint info r = evutil_getaddrinfo("www.google.com", NULL, NULL, &ai); throwing a critical heap exception when evutil_freeaddrinfo is called. This is because of improper use of freeaddrinfo when nodes within the ai structure are allocated using mm_malloc or mm_calloc (EVUTIL_AI_LIBEVENT_ALLOCATED) This adds the flag in apply_socktype_protocol_hack and walks the linked list in evutil_freeaddrinfo removing linked list nodes that are custom allocated before calling freeaddrinfo. --- diff --git a/evutil.c b/evutil.c index 69c6f205..c321eb60 100644 --- a/evutil.c +++ b/evutil.c @@ -1568,6 +1568,14 @@ apply_socktype_protocol_hack(struct evutil_addrinfo *ai) ai->ai_protocol = IPPROTO_TCP; ai_new->ai_socktype = SOCK_DGRAM; ai_new->ai_protocol = IPPROTO_UDP; + ai_new->ai_flags = EVUTIL_AI_LIBEVENT_ALLOCATED; + if (ai_new->ai_canonname != NULL) { + ai_new->ai_canonname = mm_strdup(ai_new->ai_canonname); + if (ai_new->ai_canonname == NULL) { + mm_free(ai_new); + return -1; + } + } ai_new->ai_next = ai->ai_next; ai->ai_next = ai_new; @@ -1771,11 +1779,33 @@ void evutil_freeaddrinfo(struct evutil_addrinfo *ai) { #ifdef EVENT__HAVE_GETADDRINFO - if (!(ai->ai_flags & EVUTIL_AI_LIBEVENT_ALLOCATED)) { - freeaddrinfo(ai); - return; + struct evutil_addrinfo *ai_prev = NULL; + struct evutil_addrinfo *ai_temp = ai; + /* Linked list may be the result of a native getaddrinfo() call plus + * locally allocated nodes, Before releasing it using freeaddrinfo(), + * these custom structs need to be freed separately. + */ + while (ai_temp) { + struct evutil_addrinfo *next = ai_temp->ai_next; + if (ai_temp->ai_flags & EVUTIL_AI_LIBEVENT_ALLOCATED) { + /* Remove this node from the linked list */ + if (ai_temp->ai_canonname) + mm_free(ai_temp->ai_canonname); + mm_free(ai_temp); + if (ai_prev == NULL) { + ai = next; + } else { + ai_prev->ai_next = next; + } + + } else { + ai_prev = ai_temp; + } + ai_temp = next; } -#endif + if (ai != NULL) + freeaddrinfo(ai); +#else while (ai) { struct evutil_addrinfo *next = ai->ai_next; if (ai->ai_canonname) @@ -1783,6 +1813,7 @@ evutil_freeaddrinfo(struct evutil_addrinfo *ai) mm_free(ai); ai = next; } +#endif } static evdns_getaddrinfo_fn evdns_getaddrinfo_impl = NULL; diff --git a/test/regress_util.c b/test/regress_util.c index 02cf5e19..1f919fe8 100644 --- a/test/regress_util.c +++ b/test/regress_util.c @@ -1005,6 +1005,15 @@ test_evutil_getaddrinfo(void *arg) struct evutil_addrinfo hints; int r; + /* Try NULL hint (win32 bug) */ + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + r = evutil_getaddrinfo("www.google.com", NULL, NULL, &ai); + tt_int_op(r, ==, 0); + tt_assert(ai); + evutil_freeaddrinfo(ai); + ai = NULL; + /* Try using it as a pton. */ memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC;