diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 220cd41cde..3afac87fa2 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -256,7 +256,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
 	{								      \
 	  __resolv_context_put (res_ctx);				      \
 	  result = -EAI_MEMORY;						      \
-	  goto free_and_return;						      \
+	  goto done;							      \
 	}								      \
     }									      \
   if (status == NSS_STATUS_NOTFOUND					      \
@@ -266,7 +266,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
 	{								      \
 	  __resolv_context_put (res_ctx);				      \
 	  result = -EAI_SYSTEM;						      \
-	  goto free_and_return;						      \
+	  goto done;							      \
 	}								      \
       if (h_errno == TRY_AGAIN)						      \
 	no_data = EAI_AGAIN;						      \
@@ -279,7 +279,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
 	{								      \
 	  __resolv_context_put (res_ctx);				      \
 	  result = -EAI_SYSTEM;						      \
-	  goto free_and_return;						      \
+	  goto done;							      \
 	}								      \
       *pat = addrmem;							      \
 									      \
@@ -290,7 +290,7 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
 	    {								      \
 	      __resolv_context_put (res_ctx);				      \
 	      result = -EAI_SYSTEM;					      \
-	      goto free_and_return;					      \
+	      goto done;						      \
 	    }								      \
 	  canon = canonbuf;						      \
 	}								      \
@@ -323,6 +323,123 @@ getcanonname (nss_action_list nip, struct gaih_addrtuple *at, const char *name)
   return __strdup (name);
 }
 
+static int
+process_list (const struct addrinfo *req, struct gaih_addrtuple *at,
+	      struct gaih_servtuple *st, const char *canon, bool canon_alloc,
+	      bool got_ipv6, struct addrinfo **pai, unsigned int *naddrs)
+{
+  struct gaih_servtuple *st2;
+  struct gaih_addrtuple *at2 = at;
+  size_t socklen;
+  sa_family_t family;
+
+  /*
+     buffer is the size of an unformatted IPv6 address in printable format.
+     */
+  for (at2 = at; at2 != NULL; at2 = at2->next)
+    {
+      /* Only the first entry gets the canonical name.  */
+      if (at2 == at && (req->ai_flags & AI_CANONNAME) != 0)
+	{
+	  bool do_idn = req->ai_flags & AI_CANONIDN;
+	  if (do_idn)
+	    {
+	      char *out;
+	      int rc = __idna_from_dns_encoding (canon, &out);
+	      if (rc == 0)
+		canon = out;
+	      else if (rc == EAI_IDN_ENCODE)
+		/* Use the punycode name as a fallback.  */
+		do_idn = false;
+	      else
+		return -rc;
+	    }
+	  if (!do_idn)
+	    {
+	      if (!canon_alloc)
+		{
+		  canon = __strdup (canon);
+		  if (canon == NULL)
+		    return -EAI_MEMORY;
+		}
+	    }
+	}
+
+      family = at2->family;
+      if (family == AF_INET6)
+	{
+	  socklen = sizeof (struct sockaddr_in6);
+
+	  /* If we looked up IPv4 mapped address discard them here if
+	     the caller isn't interested in all address and we have
+	     found at least one IPv6 address.  */
+	  if (got_ipv6
+	      && (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED
+	      && IN6_IS_ADDR_V4MAPPED (at2->addr))
+	    continue;
+	}
+      else
+	socklen = sizeof (struct sockaddr_in);
+
+      for (st2 = st; st2 != NULL; st2 = st2->next)
+	{
+	  struct addrinfo *ai;
+	  ai = *pai = malloc (sizeof (struct addrinfo) + socklen);
+	  if (ai == NULL)
+	    {
+	      free ((char *) canon);
+	      return -EAI_MEMORY;
+	    }
+
+	  ai->ai_flags = req->ai_flags;
+	  ai->ai_family = family;
+	  ai->ai_socktype = st2->socktype;
+	  ai->ai_protocol = st2->protocol;
+	  ai->ai_addrlen = socklen;
+	  ai->ai_addr = (void *) (ai + 1);
+
+	  /* We only add the canonical name once.  */
+	  ai->ai_canonname = (char *) canon;
+	  canon = NULL;
+
+#ifdef _HAVE_SA_LEN
+	  ai->ai_addr->sa_len = socklen;
+#endif /* _HAVE_SA_LEN */
+	  ai->ai_addr->sa_family = family;
+
+	  /* In case of an allocation error the list must be NULL
+	     terminated.  */
+	  ai->ai_next = NULL;
+
+	  if (family == AF_INET6)
+	    {
+	      struct sockaddr_in6 *sin6p =
+		(struct sockaddr_in6 *) ai->ai_addr;
+
+	      sin6p->sin6_port = st2->port;
+	      sin6p->sin6_flowinfo = 0;
+	      memcpy (&sin6p->sin6_addr,
+		      at2->addr, sizeof (struct in6_addr));
+	      sin6p->sin6_scope_id = at2->scopeid;
+	    }
+	  else
+	    {
+	      struct sockaddr_in *sinp =
+		(struct sockaddr_in *) ai->ai_addr;
+	      sinp->sin_port = st2->port;
+	      memcpy (&sinp->sin_addr,
+		      at2->addr, sizeof (struct in_addr));
+	      memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
+	    }
+
+	  pai = &(ai->ai_next);
+	}
+
+      ++*naddrs;
+    }
+  return 0;
+}
+
 static int
 gaih_inet (const char *name, const struct gaih_service *service,
 	   const struct addrinfo *req, struct addrinfo **pai,
@@ -479,7 +596,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
 	  else
 	    {
 	      result = -EAI_ADDRFAMILY;
-	      goto free_and_return;
+	      goto done;
 	    }
 
 	  if (req->ai_flags & AI_CANONNAME)
@@ -507,7 +624,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
 	      else
 		{
 		  result = -EAI_ADDRFAMILY;
-		  goto free_and_return;
+		  goto done;
 		}
 
 	      if (scope_delim != NULL
@@ -516,7 +633,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
 					   &at->scopeid) != 0)
 		{
 		  result = -EAI_NONAME;
-		  goto free_and_return;
+		  goto done;
 		}
 
 	      if (req->ai_flags & AI_CANONNAME)
@@ -555,7 +672,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
 		  if (!scratch_buffer_grow (tmpbuf))
 		    {
 		      result = -EAI_MEMORY;
-		      goto free_and_return;
+		      goto done;
 		    }
 		}
 
@@ -568,7 +685,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
 			  (req, AF_INET, h, &addrmem))
 			{
 			  result = -EAI_MEMORY;
-			  goto free_and_return;
+			  goto done;
 			}
 		      *pat = addrmem;
 		    }
@@ -578,7 +695,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
 			result = -EAI_NODATA;
 		      else
 			result = -EAI_NONAME;
-		      goto free_and_return;
+		      goto done;
 		    }
 		}
 	      else
@@ -592,10 +709,13 @@ gaih_inet (const char *name, const struct gaih_service *service,
 		       The name is known, though.  */
 		    result = -EAI_NODATA;
 
-		  goto free_and_return;
+		  goto done;
 		}
 
-	      goto process_list;
+	      if (at->family == AF_UNSPEC)
+		result = -EAI_NONAME;
+
+	      goto done;
 	    }
 
 #ifdef USE_NSCD
@@ -619,7 +739,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
 		  if (addrmem == NULL)
 		    {
 		      result = -EAI_MEMORY;
-		      goto free_and_return;
+		      goto done;
 		    }
 
 		  struct gaih_addrtuple *addrfree = addrmem;
@@ -654,7 +774,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
 			  if (canonbuf == NULL)
 			    {
 			      result = -EAI_MEMORY;
-			      goto free_and_return;
+			      goto done;
 			    }
 			  canon = (*pat)->name = canonbuf;
 			}
@@ -687,16 +807,13 @@ gaih_inet (const char *name, const struct gaih_service *service,
 		  free (air);
 
 		  if (at->family == AF_UNSPEC)
-		    {
-		      result = -EAI_NONAME;
-		      goto free_and_return;
-		    }
+		    result = -EAI_NONAME;
 
-		  goto process_list;
+		  goto done;
 		}
 	      else if (err == 0)
 		/* The database contains a negative entry.  */
-		goto free_and_return;
+		goto done;
 	      else if (__nss_not_use_nscd_hosts == 0)
 		{
 		  if (h_errno == NETDB_INTERNAL && errno == ENOMEM)
@@ -706,7 +823,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
 		  else
 		    result = -EAI_SYSTEM;
 
-		  goto free_and_return;
+		  goto done;
 		}
 	    }
 #endif
@@ -755,7 +872,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
 			{
 			  __resolv_context_put (res_ctx);
 			  result = -EAI_MEMORY;
-			  goto free_and_return;
+			  goto done;
 			}
 		    }
 
@@ -854,7 +971,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
 				{
 				  __resolv_context_put (res_ctx);
 				  result = -EAI_MEMORY;
-				  goto free_and_return;
+				  goto done;
 				}
 			      canon = canonbuf;
 			    }
@@ -903,7 +1020,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
 	      && h_errno == NETDB_INTERNAL)
 	    {
 	      result = -EAI_SYSTEM;
-	      goto free_and_return;
+	      goto done;
 	    }
 
 	  if (no_data != 0 && no_inet6_data != 0)
@@ -916,16 +1033,12 @@ gaih_inet (const char *name, const struct gaih_service *service,
 		   is known, though.  */
 		result = -EAI_NODATA;
 
-	      goto free_and_return;
+	      goto done;
 	    }
 	}
 
-    process_list:
       if (at->family == AF_UNSPEC)
-	{
-	  result = -EAI_NONAME;
-	  goto free_and_return;
-	}
+	result = -EAI_NONAME;
     }
   else
     {
@@ -955,142 +1068,16 @@ gaih_inet (const char *name, const struct gaih_service *service,
 	}
     }
 
-  {
-    struct gaih_servtuple *st2;
-    struct gaih_addrtuple *at2 = at;
-    size_t socklen;
-    sa_family_t family;
-
-    /*
-      buffer is the size of an unformatted IPv6 address in printable format.
-     */
-    while (at2 != NULL)
-      {
-	/* Only the first entry gets the canonical name.  */
-	if (at2 == at && (req->ai_flags & AI_CANONNAME) != 0)
-	  {
-	    if (canon == NULL)
-	      /* If the canonical name cannot be determined, use
-		 the passed in string.  */
-	      canon = orig_name;
-
-	    bool do_idn = req->ai_flags & AI_CANONIDN;
-	    if (do_idn)
-	      {
-		char *out;
-		int rc = __idna_from_dns_encoding (canon, &out);
-		if (rc == 0)
-		  canon = out;
-		else if (rc == EAI_IDN_ENCODE)
-		  /* Use the punycode name as a fallback.  */
-		  do_idn = false;
-		else
-		  {
-		    result = -rc;
-		    goto free_and_return;
-		  }
-	      }
-	    if (!do_idn)
-	      {
-		if (canonbuf != NULL)
-		  /* We already allocated the string using malloc, but
-		     the buffer is now owned by canon.  */
-		  canonbuf = NULL;
-		else
-		  {
-		    canon = __strdup (canon);
-		    if (canon == NULL)
-		      {
-			result = -EAI_MEMORY;
-			goto free_and_return;
-		      }
-		  }
-	      }
-	  }
-
-	family = at2->family;
-	if (family == AF_INET6)
-	  {
-	    socklen = sizeof (struct sockaddr_in6);
-
-	    /* If we looked up IPv4 mapped address discard them here if
-	       the caller isn't interested in all address and we have
-	       found at least one IPv6 address.  */
-	    if (got_ipv6
-		&& (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED
-		&& IN6_IS_ADDR_V4MAPPED (at2->addr))
-	      goto ignore;
-	  }
-	else
-	  socklen = sizeof (struct sockaddr_in);
-
-	for (st2 = st; st2 != NULL; st2 = st2->next)
-	  {
-	    struct addrinfo *ai;
-	    ai = *pai = malloc (sizeof (struct addrinfo) + socklen);
-	    if (ai == NULL)
-	      {
-		free ((char *) canon);
-		result = -EAI_MEMORY;
-		goto free_and_return;
-	      }
-
-	    ai->ai_flags = req->ai_flags;
-	    ai->ai_family = family;
-	    ai->ai_socktype = st2->socktype;
-	    ai->ai_protocol = st2->protocol;
-	    ai->ai_addrlen = socklen;
-	    ai->ai_addr = (void *) (ai + 1);
-
-	    /* We only add the canonical name once.  */
-	    ai->ai_canonname = (char *) canon;
-	    canon = NULL;
-
-#ifdef _HAVE_SA_LEN
-	    ai->ai_addr->sa_len = socklen;
-#endif /* _HAVE_SA_LEN */
-	    ai->ai_addr->sa_family = family;
-
-	    /* In case of an allocation error the list must be NULL
-	       terminated.  */
-	    ai->ai_next = NULL;
-
-	    if (family == AF_INET6)
-	      {
-		struct sockaddr_in6 *sin6p =
-		  (struct sockaddr_in6 *) ai->ai_addr;
-
-		sin6p->sin6_port = st2->port;
-		sin6p->sin6_flowinfo = 0;
-		memcpy (&sin6p->sin6_addr,
-			at2->addr, sizeof (struct in6_addr));
-		sin6p->sin6_scope_id = at2->scopeid;
-	      }
-	    else
-	      {
-		struct sockaddr_in *sinp =
-		  (struct sockaddr_in *) ai->ai_addr;
-		sinp->sin_port = st2->port;
-		memcpy (&sinp->sin_addr,
-			at2->addr, sizeof (struct in_addr));
-		memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
-	      }
-
-	    pai = &(ai->ai_next);
-	  }
-
-	++*naddrs;
-
-      ignore:
-	at2 = at2->next;
-      }
-  }
+done:
+  if (result == 0)
+    result = process_list (req, at, st, canon ?: orig_name, canonbuf != NULL,
+			   got_ipv6, pai, naddrs);
 
- free_and_return:
   if (malloc_name)
     free ((char *) name);
   free (addrmem);
-  free (canonbuf);
+  if (result != 0)
+    free (canonbuf);
 
   return result;
 }
