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