From 54d3769761e5a842aefa9462cd0eaed00da400d0 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sat, 6 Jun 2020 23:10:18 +0200 Subject: Curl_addrinfo: use one malloc instead of three To reduce the amount of allocations needed for creating a Curl_addrinfo struct, make a single larger malloc instead of three separate smaller ones. Closes #5533 --- lib/curl_addrinfo.c | 59 +++++++++++++++------------------------------------ lib/doh.c | 19 +++++------------ tests/unit/unit1305.c | 21 +++++++----------- 3 files changed, 30 insertions(+), 69 deletions(-) diff --git a/lib/curl_addrinfo.c b/lib/curl_addrinfo.c index dd07b8669..947d0d375 100644 --- a/lib/curl_addrinfo.c +++ b/lib/curl_addrinfo.c @@ -83,11 +83,8 @@ Curl_freeaddrinfo(struct Curl_addrinfo *cahead) struct Curl_addrinfo *vqualifier canext; struct Curl_addrinfo *ca; - for(ca = cahead; ca != NULL; ca = canext) { - free(ca->ai_addr); - free(ca->ai_canonname); + for(ca = cahead; ca; ca = canext) { canext = ca->ai_next; - free(ca); } } @@ -131,7 +128,7 @@ Curl_getaddrinfo_ex(const char *nodename, /* traverse the addrinfo list */ for(ai = aihead; ai != NULL; ai = ai->ai_next) { - + size_t namelen = ai->ai_canonname ? strlen(ai->ai_canonname) + 1 : 0; /* ignore elements with unsupported address family, */ /* settle family-specific sockaddr structure size. */ if(ai->ai_family == AF_INET) @@ -151,7 +148,7 @@ Curl_getaddrinfo_ex(const char *nodename, if((size_t)ai->ai_addrlen < ss_size) continue; - ca = malloc(sizeof(struct Curl_addrinfo)); + ca = malloc(sizeof(struct Curl_addrinfo) + ss_size + namelen); if(!ca) { error = EAI_MEMORY; break; @@ -169,22 +166,12 @@ Curl_getaddrinfo_ex(const char *nodename, ca->ai_canonname = NULL; ca->ai_next = NULL; - ca->ai_addr = malloc(ss_size); - if(!ca->ai_addr) { - error = EAI_MEMORY; - free(ca); - break; - } + ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo)); memcpy(ca->ai_addr, ai->ai_addr, ss_size); - if(ai->ai_canonname != NULL) { - ca->ai_canonname = strdup(ai->ai_canonname); - if(!ca->ai_canonname) { - error = EAI_MEMORY; - free(ca->ai_addr); - free(ca); - break; - } + if(namelen) { + ca->ai_canonname = (void *)((char *)ca->ai_addr + ss_size); + memcpy(ca->ai_canonname, ai->ai_canonname, namelen); } /* if the return list is empty, this becomes the first element */ @@ -289,8 +276,8 @@ Curl_he2ai(const struct hostent *he, int port) DEBUGASSERT((he->h_name != NULL) && (he->h_addr_list != NULL)); for(i = 0; (curr = he->h_addr_list[i]) != NULL; i++) { - size_t ss_size; + size_t namelen = strlen(he->h_name) + 1; /* include zero termination */ #ifdef ENABLE_IPV6 if(he->h_addrtype == AF_INET6) ss_size = sizeof(struct sockaddr_in6); @@ -298,24 +285,17 @@ Curl_he2ai(const struct hostent *he, int port) #endif ss_size = sizeof(struct sockaddr_in); - ai = calloc(1, sizeof(struct Curl_addrinfo)); + /* allocate memory to told the struct, the address and the name */ + ai = calloc(1, sizeof(struct Curl_addrinfo) + ss_size + namelen); if(!ai) { result = CURLE_OUT_OF_MEMORY; break; } - ai->ai_canonname = strdup(he->h_name); - if(!ai->ai_canonname) { - result = CURLE_OUT_OF_MEMORY; - free(ai); - break; - } - ai->ai_addr = calloc(1, ss_size); - if(!ai->ai_addr) { - result = CURLE_OUT_OF_MEMORY; - free(ai->ai_canonname); - free(ai); - break; - } + /* put the address after the struct */ + ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo)); + /* then put the name after the address */ + ai->ai_canonname = (char *)ai->ai_addr + ss_size; + memcpy(ai->ai_canonname, he->h_name, namelen); if(!firstai) /* store the pointer we want to return from this function */ @@ -496,14 +476,10 @@ struct Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, *longpath = FALSE; - ai = calloc(1, sizeof(struct Curl_addrinfo)); + ai = calloc(1, sizeof(struct Curl_addrinfo) + sizeof(struct sockaddr_un)); if(!ai) return NULL; - ai->ai_addr = calloc(1, sizeof(struct sockaddr_un)); - if(!ai->ai_addr) { - free(ai); - return NULL; - } + ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo)); sa_un = (void *) ai->ai_addr; sa_un->sun_family = AF_UNIX; @@ -511,7 +487,6 @@ struct Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, /* sun_path must be able to store the NUL-terminated path */ path_len = strlen(path) + 1; if(path_len > sizeof(sa_un->sun_path)) { - free(ai->ai_addr); free(ai); *longpath = TRUE; return NULL; diff --git a/lib/doh.c b/lib/doh.c index 8f9e42c33..ebb2c243b 100644 --- a/lib/doh.c +++ b/lib/doh.c @@ -803,6 +803,7 @@ doh2ai(const struct dohentry *de, const char *hostname, int port) #endif CURLcode result = CURLE_OK; int i; + size_t hostlen = strlen(hostname) + 1; /* include zero terminator */ if(!de) /* no input == no output! */ @@ -825,24 +826,14 @@ doh2ai(const struct dohentry *de, const char *hostname, int port) addrtype = AF_INET; } - ai = calloc(1, sizeof(struct Curl_addrinfo)); + ai = calloc(1, sizeof(struct Curl_addrinfo) + ss_size + hostlen); if(!ai) { result = CURLE_OUT_OF_MEMORY; break; } - ai->ai_canonname = strdup(hostname); - if(!ai->ai_canonname) { - result = CURLE_OUT_OF_MEMORY; - free(ai); - break; - } - ai->ai_addr = calloc(1, ss_size); - if(!ai->ai_addr) { - result = CURLE_OUT_OF_MEMORY; - free(ai->ai_canonname); - free(ai); - break; - } + ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo)); + ai->ai_canonname = (void *)((char *)ai->ai_addr + ss_size); + memcpy(ai->ai_canonname, hostname, hostlen); if(!firstai) /* store the pointer we want to return from this function */ diff --git a/tests/unit/unit1305.c b/tests/unit/unit1305.c index f3cd9d8f0..50f6da8bb 100644 --- a/tests/unit/unit1305.c +++ b/tests/unit/unit1305.c @@ -76,23 +76,18 @@ static void unit_stop(void) static struct Curl_addrinfo *fake_ai(void) { static struct Curl_addrinfo *ai; + static const char dummy[]="dummy"; + size_t namelen = sizeof(dummy); /* including the zero terminator */ - ai = calloc(1, sizeof(struct Curl_addrinfo)); + ai = calloc(1, sizeof(struct Curl_addrinfo) + sizeof(struct sockaddr_in) + + namelen); if(!ai) return NULL; - ai->ai_canonname = strdup("dummy"); - if(!ai->ai_canonname) { - free(ai); - return NULL; - } - - ai->ai_addr = calloc(1, sizeof(struct sockaddr_in)); - if(!ai->ai_addr) { - free(ai->ai_canonname); - free(ai); - return NULL; - } + ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo)); + ai->ai_canonname = (void *)((char *)ai->ai_addr + + sizeof(struct sockaddr_in)); + memcpy(ai->ai_canonname, dummy, namelen); ai->ai_family = AF_INET; ai->ai_addrlen = sizeof(struct sockaddr_in); -- cgit v1.2.3