about summary refs log tree commit diff
path: root/sysdeps/unix/sysv/linux
diff options
context:
space:
mode:
authorOndřej Bílka <neleai@seznam.cz>2015-01-06 17:26:44 +0100
committerOndřej Bílka <neleai@seznam.cz>2015-01-06 17:26:44 +0100
commit4790d9a2c0a04964a5e0caf2af18b813d8fd4008 (patch)
treec1046b5103c551efa0f51343a9236b6f9c23b09d /sysdeps/unix/sysv/linux
parent14bb4e57c094849228ad8524693ab9432c38396c (diff)
downloadglibc-4790d9a2c0a04964a5e0caf2af18b813d8fd4008.tar.gz
glibc-4790d9a2c0a04964a5e0caf2af18b813d8fd4008.tar.xz
glibc-4790d9a2c0a04964a5e0caf2af18b813d8fd4008.zip
Clean up check_pf allocation pattern. addresses
We simplify allocation strategy there so instead of using temporary linked list
and then copying entries to output array we keep them in resizable
array.
Diffstat (limited to 'sysdeps/unix/sysv/linux')
-rw-r--r--sysdeps/unix/sysv/linux/check_pf.c123
1 files changed, 39 insertions, 84 deletions
diff --git a/sysdeps/unix/sysv/linux/check_pf.c b/sysdeps/unix/sysv/linux/check_pf.c
index d7efe72d7f..162606d7ab 100644
--- a/sysdeps/unix/sysv/linux/check_pf.c
+++ b/sysdeps/unix/sysv/linux/check_pf.c
@@ -105,6 +105,11 @@ cache_valid_p (void)
 static struct cached_data *
 make_request (int fd, pid_t pid)
 {
+  struct cached_data *result = NULL;
+
+  size_t result_len = 0;
+  size_t result_cap = 32;
+
   struct req
   {
     struct nlmsghdr nlh;
@@ -130,26 +135,11 @@ make_request (int fd, pid_t pid)
   nladdr.nl_family = AF_NETLINK;
 
 #ifdef PAGE_SIZE
-  /* Help the compiler optimize out the malloc call if PAGE_SIZE
-     is constant and smaller or equal to PTHREAD_STACK_MIN/4.  */
   const size_t buf_size = PAGE_SIZE;
 #else
-  const size_t buf_size = __getpagesize ();
+  const size_t buf_size = 4096;
 #endif
-  bool use_malloc = false;
-  char *buf;
-  size_t alloca_used = 0;
-
-  if (__libc_use_alloca (buf_size))
-    buf = alloca_account (buf_size, alloca_used);
-  else
-    {
-      buf = malloc (buf_size);
-      if (buf != NULL)
-	use_malloc = true;
-      else
-	goto out_fail;
-    }
+  char buf[buf_size];
 
   struct iovec iov = { buf, buf_size };
 
@@ -159,13 +149,7 @@ make_request (int fd, pid_t pid)
     goto out_fail;
 
   bool done = false;
-  struct in6ailist
-  {
-    struct in6addrinfo info;
-    struct in6ailist *next;
-    bool use_malloc;
-  } *in6ailist = NULL;
-  size_t in6ailistlen = 0;
+
   bool seen_ipv4 = false;
   bool seen_ipv6 = false;
 
@@ -181,10 +165,10 @@ make_request (int fd, pid_t pid)
 
       ssize_t read_len = TEMP_FAILURE_RETRY (__recvmsg (fd, &msg, 0));
       if (read_len <= 0)
-	goto out_fail2;
+	goto out_fail;
 
       if (msg.msg_flags & MSG_TRUNC)
-	goto out_fail2;
+	goto out_fail;
 
       struct nlmsghdr *nlmh;
       for (nlmh = (struct nlmsghdr *) buf;
@@ -240,40 +224,35 @@ make_request (int fd, pid_t pid)
 		    }
 		}
 
-	      struct in6ailist *newp;
-	      if (__libc_use_alloca (alloca_used + sizeof (*newp)))
+	      if (result_len == 0 || result_len == result_cap)
 		{
-		  newp = alloca_account (sizeof (*newp), alloca_used);
-		  newp->use_malloc = false;
+		  result_cap = 2 * result_cap;
+		  result = realloc (result, sizeof (*result)
+				    + result_cap
+				      * sizeof (struct in6addrinfo));
 		}
-	      else
-		{
-		  newp = malloc (sizeof (*newp));
-		  if (newp == NULL)
-		    goto out_fail2;
-		  newp->use_malloc = true;
-		}
-	      newp->info.flags = (((ifam->ifa_flags
-				    & (IFA_F_DEPRECATED
-				       | IFA_F_OPTIMISTIC))
-				   ? in6ai_deprecated : 0)
-				  | ((ifam->ifa_flags
-				      & IFA_F_HOMEADDRESS)
-				     ? in6ai_homeaddress : 0));
-	      newp->info.prefixlen = ifam->ifa_prefixlen;
-	      newp->info.index = ifam->ifa_index;
+
+	      if (!result)
+		goto out_fail;
+
+	      struct in6addrinfo *info = &result->in6ai[result_len++];
+
+	      info->flags = (((ifam->ifa_flags
+			       & (IFA_F_DEPRECATED | IFA_F_OPTIMISTIC))
+			      ? in6ai_deprecated : 0)
+			     | ((ifam->ifa_flags & IFA_F_HOMEADDRESS)
+			         ? in6ai_homeaddress : 0));
+	      info->prefixlen = ifam->ifa_prefixlen;
+	      info->index = ifam->ifa_index;
 	      if (ifam->ifa_family == AF_INET)
 		{
-		  newp->info.addr[0] = 0;
-		  newp->info.addr[1] = 0;
-		  newp->info.addr[2] = htonl (0xffff);
-		  newp->info.addr[3] = *(const in_addr_t *) address;
+		  info->addr[0] = 0;
+		  info->addr[1] = 0;
+		  info->addr[2] = htonl (0xffff);
+		  info->addr[3] = *(const in_addr_t *) address;
 		}
 	      else
-		memcpy (newp->info.addr, address, sizeof (newp->info.addr));
-	      newp->next = in6ailist;
-	      in6ailist = newp;
-	      ++in6ailistlen;
+		memcpy (info->addr, address, sizeof (info->addr));
 	    }
 	  else if (nlmh->nlmsg_type == NLMSG_DONE)
 	    /* We found the end, leave the loop.  */
@@ -282,53 +261,29 @@ make_request (int fd, pid_t pid)
     }
   while (! done);
 
-  struct cached_data *result;
-  if (seen_ipv6 && in6ailist != NULL)
+  if (seen_ipv6 && result != NULL)
     {
-      result = malloc (sizeof (*result)
-		       + in6ailistlen * sizeof (struct in6addrinfo));
-      if (result == NULL)
-	goto out_fail2;
-
       result->timestamp = get_nl_timestamp ();
       result->usecnt = 2;
       result->seen_ipv4 = seen_ipv4;
       result->seen_ipv6 = true;
-      result->in6ailen = in6ailistlen;
-
-      do
-	{
-	  result->in6ai[--in6ailistlen] = in6ailist->info;
-	  struct in6ailist *next = in6ailist->next;
-	  if (in6ailist->use_malloc)
-	    free (in6ailist);
-	  in6ailist = next;
-	}
-      while (in6ailist != NULL);
+      result->in6ailen = result_len;
     }
   else
     {
+      free (result);
+
       atomic_add (&noai6ai_cached.usecnt, 2);
       noai6ai_cached.seen_ipv4 = seen_ipv4;
       noai6ai_cached.seen_ipv6 = seen_ipv6;
       result = &noai6ai_cached;
     }
 
-  if (use_malloc)
-    free (buf);
   return result;
 
- out_fail2:
-  while (in6ailist != NULL)
-    {
-      struct in6ailist *next = in6ailist->next;
-      if (in6ailist->use_malloc)
-	free (in6ailist);
-      in6ailist = next;
-    }
  out_fail:
-  if (use_malloc)
-    free (buf);
+
+  free (result);
   return NULL;
 }