]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
Curl_addrinfo: use one malloc instead of three
authorDaniel Stenberg <daniel@haxx.se>
Sat, 6 Jun 2020 21:10:18 +0000 (23:10 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Mon, 8 Jun 2020 14:10:53 +0000 (16:10 +0200)
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
lib/doh.c
tests/unit/unit1305.c

index dd07b8669a9248f19921abbc32a80b19db0e973e..947d0d37567fef1b20f7803bbafa9aac301bfeef 100644 (file)
@@ -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;
index 8f9e42c33d899307fc537e427f982c102b0a122b..ebb2c243bc661d4f8a9a57db9f137b88f6558b34 100644 (file)
--- 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 */
index f3cd9d8f067c04bb750215ae07232576569c65f4..50f6da8bb81a7a1d6253b2412d97c6d22654b32f 100644 (file)
@@ -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);