Zebediah Figura : ws2_32: Allocate the addrinfo buffer on the PE side.

Alexandre Julliard julliard at winehq.org
Wed Aug 4 16:41:36 CDT 2021


Module: wine
Branch: master
Commit: d6555b966ecb80da673a20bdfea0a1562187c937
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=d6555b966ecb80da673a20bdfea0a1562187c937

Author: Zebediah Figura <zfigura at codeweavers.com>
Date:   Tue Aug  3 23:53:34 2021 -0500

ws2_32: Allocate the addrinfo buffer on the PE side.

Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ws2_32/protocol.c       | 44 +++++++++++++++++++-------
 dlls/ws2_32/unixlib.c        | 75 +++++++++++++++++++-------------------------
 dlls/ws2_32/ws2_32_private.h |  4 +--
 3 files changed, 67 insertions(+), 56 deletions(-)

diff --git a/dlls/ws2_32/protocol.c b/dlls/ws2_32/protocol.c
index 7b6e68555b0..eb97e0d612d 100644
--- a/dlls/ws2_32/protocol.c
+++ b/dlls/ws2_32/protocol.c
@@ -130,6 +130,33 @@ static char *get_fqdn(void)
     return ret;
 }
 
+/* call Unix getaddrinfo, allocating a large enough buffer */
+static int do_getaddrinfo( const char *node, const char *service,
+                           const struct WS_addrinfo *hints, struct WS_addrinfo **info )
+{
+    struct WS_addrinfo *buffer, *new_buffer;
+    unsigned int size = 1024;
+    int ret;
+
+    if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size )))
+        return WSA_NOT_ENOUGH_MEMORY;
+
+    while ((ret = unix_funcs->getaddrinfo( node, service, hints, buffer, &size )) == ERROR_INSUFFICIENT_BUFFER)
+    {
+        if (!(new_buffer = HeapReAlloc( GetProcessHeap(), 0, buffer, size )))
+        {
+            HeapFree( GetProcessHeap(), 0, buffer );
+            return WSA_NOT_ENOUGH_MEMORY;
+        }
+        buffer = new_buffer;
+    }
+
+    if (!ret)
+        *info = buffer;
+    else
+        HeapFree( GetProcessHeap(), 0, buffer );
+    return ret;
+}
 
 
 /***********************************************************************
@@ -173,7 +200,7 @@ int WINAPI WS_getaddrinfo( const char *node, const char *service,
         }
     }
 
-    ret = unix_funcs->getaddrinfo( node, service, hints, info );
+    ret = do_getaddrinfo( node, service, hints, info );
 
     if (ret && (!hints || !(hints->ai_flags & WS_AI_NUMERICHOST)) && node)
     {
@@ -188,7 +215,7 @@ int WINAPI WS_getaddrinfo( const char *node, const char *service,
              * by sending a NULL host and avoid sending a NULL servname too because that
              * is invalid */
             ERR_(winediag)( "Failed to resolve your host name IP\n" );
-            ret = unix_funcs->getaddrinfo( NULL, service, hints, info );
+            ret = do_getaddrinfo( NULL, service, hints, info );
             if (!ret && hints && (hints->ai_flags & WS_AI_CANONNAME) && *info && !(*info)->ai_canonname)
             {
                 WS_freeaddrinfo( *info );
@@ -542,18 +569,11 @@ int WINAPI GetAddrInfoW(const WCHAR *nodename, const WCHAR *servname, const ADDR
 /***********************************************************************
  *      freeaddrinfo   (ws2_32.@)
  */
-void WINAPI WS_freeaddrinfo( struct WS_addrinfo *res )
+void WINAPI WS_freeaddrinfo( struct WS_addrinfo *info )
 {
-    while (res)
-    {
-        struct WS_addrinfo *next;
+    TRACE( "%p\n", info );
 
-        HeapFree( GetProcessHeap(), 0, res->ai_canonname );
-        HeapFree( GetProcessHeap(), 0, res->ai_addr );
-        next = res->ai_next;
-        HeapFree( GetProcessHeap(), 0, res );
-        res = next;
-    }
+    HeapFree( GetProcessHeap(), 0, info );
 }
 
 
diff --git a/dlls/ws2_32/unixlib.c b/dlls/ws2_32/unixlib.c
index 4b63e8e6415..2ed8ce2f762 100644
--- a/dlls/ws2_32/unixlib.c
+++ b/dlls/ws2_32/unixlib.c
@@ -468,17 +468,16 @@ static BOOL addrinfo_in_list( const struct WS_addrinfo *list, const struct WS_ad
     return FALSE;
 }
 
-static int CDECL unix_getaddrinfo( const char *node, const char *service,
-                                   const struct WS_addrinfo *hints, struct WS_addrinfo **info )
+static int CDECL unix_getaddrinfo( const char *node, const char *service, const struct WS_addrinfo *hints,
+                                   struct WS_addrinfo *info, unsigned int *size )
 {
 #ifdef HAVE_GETADDRINFO
     struct addrinfo unix_hints = {0};
     struct addrinfo *unix_info, *src;
     struct WS_addrinfo *dst, *prev = NULL;
+    unsigned int needed_size = 0;
     int ret;
 
-    *info = NULL;
-
     /* servname tweak required by OSX and BSD kernels */
     if (service && !service[0]) service = "0";
 
@@ -528,12 +527,28 @@ static int CDECL unix_getaddrinfo( const char *node, const char *service,
     if (ret)
         return addrinfo_err_from_unix( ret );
 
-    *info = NULL;
+    for (src = unix_info; src != NULL; src = src->ai_next)
+    {
+        needed_size += sizeof(struct WS_addrinfo);
+        if (src->ai_canonname)
+            needed_size += strlen( src->ai_canonname ) + 1;
+        needed_size += sockaddr_from_unix( (const union unix_sockaddr *)src->ai_addr, NULL, 0 );
+    }
+
+    if (*size < needed_size)
+    {
+        *size = needed_size;
+        freeaddrinfo( unix_info );
+        return ERROR_INSUFFICIENT_BUFFER;
+    }
+
+    dst = info;
+
+    memset( info, 0, needed_size );
 
     for (src = unix_info; src != NULL; src = src->ai_next)
     {
-        if (!(dst = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*dst) )))
-            goto fail;
+        void *next = dst + 1;
 
         dst->ai_flags = addrinfo_flags_from_unix( src->ai_flags );
         dst->ai_family = family_from_unix( src->ai_family );
@@ -549,55 +564,31 @@ static int CDECL unix_getaddrinfo( const char *node, const char *service,
         }
         if (src->ai_canonname)
         {
-            if (!(dst->ai_canonname = RtlAllocateHeap( GetProcessHeap(), 0, strlen( src->ai_canonname ) + 1 )))
-            {
-                RtlFreeHeap( GetProcessHeap(), 0, dst );
-                goto fail;
-            }
-            strcpy( dst->ai_canonname, src->ai_canonname );
+            size_t len = strlen( src->ai_canonname ) + 1;
+
+            dst->ai_canonname = next;
+            memcpy( dst->ai_canonname, src->ai_canonname, len );
+            next = dst->ai_canonname + len;
         }
 
         dst->ai_addrlen = sockaddr_from_unix( (const union unix_sockaddr *)src->ai_addr, NULL, 0 );
-        if (!(dst->ai_addr = RtlAllocateHeap( GetProcessHeap(), 0, dst->ai_addrlen )))
-        {
-            RtlFreeHeap( GetProcessHeap(), 0, dst->ai_canonname );
-            RtlFreeHeap( GetProcessHeap(), 0, dst );
-            goto fail;
-        }
+        dst->ai_addr = next;
         sockaddr_from_unix( (const union unix_sockaddr *)src->ai_addr, dst->ai_addr, dst->ai_addrlen );
+        next = (char *)dst->ai_addr + dst->ai_addrlen;
 
-        if (addrinfo_in_list( *info, dst ))
-        {
-            RtlFreeHeap( GetProcessHeap(), 0, dst->ai_canonname );
-            RtlFreeHeap( GetProcessHeap(), 0, dst->ai_addr );
-            RtlFreeHeap( GetProcessHeap(), 0, dst );
-        }
-        else
+        if (dst == info || !addrinfo_in_list( info, dst ))
         {
             if (prev)
                 prev->ai_next = dst;
-            else
-                *info = dst;
             prev = dst;
+            dst = next;
         }
     }
 
+    dst->ai_next = NULL;
+
     freeaddrinfo( unix_info );
     return 0;
-
-fail:
-    dst = *info;
-    while (dst)
-    {
-        struct WS_addrinfo *next;
-
-        RtlFreeHeap( GetProcessHeap(), 0, dst->ai_canonname );
-        RtlFreeHeap( GetProcessHeap(), 0, dst->ai_addr );
-        next = dst->ai_next;
-        RtlFreeHeap( GetProcessHeap(), 0, dst );
-        dst = next;
-    }
-    return WS_EAI_MEMORY;
 #else
     FIXME( "getaddrinfo() not found during build time\n" );
     return WS_EAI_FAIL;
diff --git a/dlls/ws2_32/ws2_32_private.h b/dlls/ws2_32/ws2_32_private.h
index 5fd083eac31..5c0f0af5bd9 100644
--- a/dlls/ws2_32/ws2_32_private.h
+++ b/dlls/ws2_32/ws2_32_private.h
@@ -198,8 +198,8 @@ struct per_thread_data *get_per_thread_data(void) DECLSPEC_HIDDEN;
 
 struct unix_funcs
 {
-    int (CDECL *getaddrinfo)( const char *node, const char *service,
-                              const struct WS(addrinfo) *hints, struct WS(addrinfo) **info );
+    int (CDECL *getaddrinfo)( const char *node, const char *service, const struct WS(addrinfo) *hints,
+                              struct WS(addrinfo) *info, unsigned int *size );
 };
 
 extern const struct unix_funcs *unix_funcs;




More information about the wine-cvs mailing list