e67796
commit 228cdb00a045ae3b68a91b35c7548bab6029446e
e67796
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
e67796
Date:   Thu Mar 17 11:44:34 2022 +0530
e67796
e67796
    Simplify allocations and fix merge and continue actions [BZ #28931]
e67796
    
e67796
    Allocations for address tuples is currently a bit confusing because of
e67796
    the pointer chasing through PAT, making it hard to observe the sequence
e67796
    in which allocations have been made.  Narrow scope of the pointer
e67796
    chasing through PAT so that it is only used where necessary.
e67796
    
e67796
    This also tightens actions behaviour with the hosts database in
e67796
    getaddrinfo to comply with the manual text.  The "continue" action
e67796
    discards previous results and the "merge" action results in an immedate
e67796
    lookup failure.  Consequently, chaining of allocations across modules is
e67796
    no longer necessary, thus opening up cleanup opportunities.
e67796
    
e67796
    A test has been added that checks some combinations to ensure that they
e67796
    work correctly.
e67796
    
e67796
    Resolves: BZ #28931
e67796
    
e67796
    Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
e67796
    Reviewed-by: DJ Delorie <dj@redhat.com>
e67796
    (cherry picked from commit 1c37b8022e8763fedbb3f79c02e05c6acfe5a215)
e67796
e67796
Conflicts:
e67796
	nss/Makefile
e67796
	(Missing test cases)
e67796
	sysdeps/posix/getaddrinfo.c
e67796
	(RES_USE_INET6 still present in RHEL-8 and NSS module traversal rewrite
e67796
	not in RHEL-8)
e67796
e67796
diff --git a/nss/Makefile b/nss/Makefile
e67796
index e8a7d9c7b3cefcdf..cfb255c6e7a3a4de 100644
e67796
--- a/nss/Makefile
e67796
+++ b/nss/Makefile
e67796
@@ -65,7 +65,8 @@ xtests			= bug-erange
e67796
 
e67796
 tests-container = \
e67796
 			  tst-nss-db-endpwent \
e67796
-			  tst-nss-db-endgrent
e67796
+			  tst-nss-db-endgrent \
e67796
+			  tst-nss-gai-actions
e67796
 
e67796
 # Tests which need libdl
e67796
 ifeq (yes,$(build-shared))
e67796
diff --git a/nss/tst-nss-gai-actions.c b/nss/tst-nss-gai-actions.c
e67796
new file mode 100644
e67796
index 0000000000000000..efca6cd1837a172a
e67796
--- /dev/null
e67796
+++ b/nss/tst-nss-gai-actions.c
e67796
@@ -0,0 +1,149 @@
e67796
+/* Test continue and merge NSS actions for getaddrinfo.
e67796
+   Copyright The GNU Toolchain Authors.
e67796
+   This file is part of the GNU C Library.
e67796
+
e67796
+   The GNU C Library is free software; you can redistribute it and/or
e67796
+   modify it under the terms of the GNU Lesser General Public
e67796
+   License as published by the Free Software Foundation; either
e67796
+   version 2.1 of the License, or (at your option) any later version.
e67796
+
e67796
+   The GNU C Library is distributed in the hope that it will be useful,
e67796
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
e67796
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
e67796
+   Lesser General Public License for more details.
e67796
+
e67796
+   You should have received a copy of the GNU Lesser General Public
e67796
+   License along with the GNU C Library; if not, see
e67796
+   <https://www.gnu.org/licenses/>.  */
e67796
+
e67796
+#include <dlfcn.h>
e67796
+#include <gnu/lib-names.h>
e67796
+#include <nss.h>
e67796
+#include <stdio.h>
e67796
+#include <stdlib.h>
e67796
+#include <string.h>
e67796
+
e67796
+#include <support/check.h>
e67796
+#include <support/format_nss.h>
e67796
+#include <support/support.h>
e67796
+#include <support/xstdio.h>
e67796
+#include <support/xunistd.h>
e67796
+
e67796
+enum
e67796
+{
e67796
+  ACTION_MERGE = 0,
e67796
+  ACTION_CONTINUE,
e67796
+};
e67796
+
e67796
+static const char *
e67796
+family_str (int family)
e67796
+{
e67796
+  switch (family)
e67796
+    {
e67796
+    case AF_UNSPEC:
e67796
+      return "AF_UNSPEC";
e67796
+    case AF_INET:
e67796
+      return "AF_INET";
e67796
+    default:
e67796
+      __builtin_unreachable ();
e67796
+    }
e67796
+}
e67796
+
e67796
+static const char *
e67796
+action_str (int action)
e67796
+{
e67796
+  switch (action)
e67796
+    {
e67796
+    case ACTION_MERGE:
e67796
+      return "merge";
e67796
+    case ACTION_CONTINUE:
e67796
+      return "continue";
e67796
+    default:
e67796
+      __builtin_unreachable ();
e67796
+    }
e67796
+}
e67796
+
e67796
+static void
e67796
+do_one_test (int action, int family, bool canon)
e67796
+{
e67796
+  struct addrinfo hints =
e67796
+    {
e67796
+      .ai_family = family,
e67796
+    };
e67796
+
e67796
+  struct addrinfo *ai;
e67796
+
e67796
+  if (canon)
e67796
+    hints.ai_flags = AI_CANONNAME;
e67796
+
e67796
+  printf ("***** Testing \"files [SUCCESS=%s] files\" for family %s, %s\n",
e67796
+	  action_str (action), family_str (family),
e67796
+	  canon ? "AI_CANONNAME" : "");
e67796
+
e67796
+  int ret = getaddrinfo ("example.org", "80", &hints, &ai;;
e67796
+
e67796
+  switch (action)
e67796
+    {
e67796
+    case ACTION_MERGE:
e67796
+      if (ret == 0)
e67796
+	{
e67796
+	  char *formatted = support_format_addrinfo (ai, ret);
e67796
+
e67796
+	  printf ("merge unexpectedly succeeded:\n %s\n", formatted);
e67796
+	  support_record_failure ();
e67796
+	  free (formatted);
e67796
+	}
e67796
+      else
e67796
+	return;
e67796
+    case ACTION_CONTINUE:
e67796
+	{
e67796
+	  char *formatted = support_format_addrinfo (ai, ret);
e67796
+
e67796
+	  /* Verify that the result appears exactly once.  */
e67796
+	  const char *expected = "address: STREAM/TCP 192.0.0.1 80\n"
e67796
+	    "address: DGRAM/UDP 192.0.0.1 80\n"
e67796
+	    "address: RAW/IP 192.0.0.1 80\n";
e67796
+
e67796
+	  const char *contains = strstr (formatted, expected);
e67796
+	  const char *contains2 = NULL;
e67796
+
e67796
+	  if (contains != NULL)
e67796
+	    contains2 = strstr (contains + strlen (expected), expected);
e67796
+
e67796
+	  if (contains == NULL || contains2 != NULL)
e67796
+	    {
e67796
+	      printf ("continue failed:\n%s\n", formatted);
e67796
+	      support_record_failure ();
e67796
+	    }
e67796
+
e67796
+	  free (formatted);
e67796
+	  break;
e67796
+	}
e67796
+    default:
e67796
+      __builtin_unreachable ();
e67796
+    }
e67796
+}
e67796
+
e67796
+static void
e67796
+do_one_test_set (int action)
e67796
+{
e67796
+  char buf[32];
e67796
+
e67796
+  snprintf (buf, sizeof (buf), "files [SUCCESS=%s] files",
e67796
+	    action_str (action));
e67796
+  __nss_configure_lookup ("hosts", buf);
e67796
+
e67796
+  do_one_test (action, AF_UNSPEC, false);
e67796
+  do_one_test (action, AF_INET, false);
e67796
+  do_one_test (action, AF_INET, true);
e67796
+}
e67796
+
e67796
+static int
e67796
+do_test (void)
e67796
+{
e67796
+  do_one_test_set (ACTION_CONTINUE);
e67796
+  do_one_test_set (ACTION_MERGE);
e67796
+  return 0;
e67796
+}
e67796
+
e67796
+#include <support/test-driver.c>
e67796
diff --git a/nss/tst-nss-gai-actions.root/etc/host.conf b/nss/tst-nss-gai-actions.root/etc/host.conf
e67796
new file mode 100644
e67796
index 0000000000000000..d1a59f73a90f2993
e67796
--- /dev/null
e67796
+++ b/nss/tst-nss-gai-actions.root/etc/host.conf
e67796
@@ -0,0 +1 @@
e67796
+multi on
e67796
diff --git a/nss/tst-nss-gai-actions.root/etc/hosts b/nss/tst-nss-gai-actions.root/etc/hosts
e67796
new file mode 100644
e67796
index 0000000000000000..50ce9774dc2c21d9
e67796
--- /dev/null
e67796
+++ b/nss/tst-nss-gai-actions.root/etc/hosts
e67796
@@ -0,0 +1,508 @@
e67796
+192.0.0.1	example.org
e67796
+192.0.0.2	example.org
e67796
+192.0.0.3	example.org
e67796
+192.0.0.4	example.org
e67796
+192.0.0.5	example.org
e67796
+192.0.0.6	example.org
e67796
+192.0.0.7	example.org
e67796
+192.0.0.8	example.org
e67796
+192.0.0.9	example.org
e67796
+192.0.0.10	example.org
e67796
+192.0.0.11	example.org
e67796
+192.0.0.12	example.org
e67796
+192.0.0.13	example.org
e67796
+192.0.0.14	example.org
e67796
+192.0.0.15	example.org
e67796
+192.0.0.16	example.org
e67796
+192.0.0.17	example.org
e67796
+192.0.0.18	example.org
e67796
+192.0.0.19	example.org
e67796
+192.0.0.20	example.org
e67796
+192.0.0.21	example.org
e67796
+192.0.0.22	example.org
e67796
+192.0.0.23	example.org
e67796
+192.0.0.24	example.org
e67796
+192.0.0.25	example.org
e67796
+192.0.0.26	example.org
e67796
+192.0.0.27	example.org
e67796
+192.0.0.28	example.org
e67796
+192.0.0.29	example.org
e67796
+192.0.0.30	example.org
e67796
+192.0.0.31	example.org
e67796
+192.0.0.32	example.org
e67796
+192.0.0.33	example.org
e67796
+192.0.0.34	example.org
e67796
+192.0.0.35	example.org
e67796
+192.0.0.36	example.org
e67796
+192.0.0.37	example.org
e67796
+192.0.0.38	example.org
e67796
+192.0.0.39	example.org
e67796
+192.0.0.40	example.org
e67796
+192.0.0.41	example.org
e67796
+192.0.0.42	example.org
e67796
+192.0.0.43	example.org
e67796
+192.0.0.44	example.org
e67796
+192.0.0.45	example.org
e67796
+192.0.0.46	example.org
e67796
+192.0.0.47	example.org
e67796
+192.0.0.48	example.org
e67796
+192.0.0.49	example.org
e67796
+192.0.0.50	example.org
e67796
+192.0.0.51	example.org
e67796
+192.0.0.52	example.org
e67796
+192.0.0.53	example.org
e67796
+192.0.0.54	example.org
e67796
+192.0.0.55	example.org
e67796
+192.0.0.56	example.org
e67796
+192.0.0.57	example.org
e67796
+192.0.0.58	example.org
e67796
+192.0.0.59	example.org
e67796
+192.0.0.60	example.org
e67796
+192.0.0.61	example.org
e67796
+192.0.0.62	example.org
e67796
+192.0.0.63	example.org
e67796
+192.0.0.64	example.org
e67796
+192.0.0.65	example.org
e67796
+192.0.0.66	example.org
e67796
+192.0.0.67	example.org
e67796
+192.0.0.68	example.org
e67796
+192.0.0.69	example.org
e67796
+192.0.0.70	example.org
e67796
+192.0.0.71	example.org
e67796
+192.0.0.72	example.org
e67796
+192.0.0.73	example.org
e67796
+192.0.0.74	example.org
e67796
+192.0.0.75	example.org
e67796
+192.0.0.76	example.org
e67796
+192.0.0.77	example.org
e67796
+192.0.0.78	example.org
e67796
+192.0.0.79	example.org
e67796
+192.0.0.80	example.org
e67796
+192.0.0.81	example.org
e67796
+192.0.0.82	example.org
e67796
+192.0.0.83	example.org
e67796
+192.0.0.84	example.org
e67796
+192.0.0.85	example.org
e67796
+192.0.0.86	example.org
e67796
+192.0.0.87	example.org
e67796
+192.0.0.88	example.org
e67796
+192.0.0.89	example.org
e67796
+192.0.0.90	example.org
e67796
+192.0.0.91	example.org
e67796
+192.0.0.92	example.org
e67796
+192.0.0.93	example.org
e67796
+192.0.0.94	example.org
e67796
+192.0.0.95	example.org
e67796
+192.0.0.96	example.org
e67796
+192.0.0.97	example.org
e67796
+192.0.0.98	example.org
e67796
+192.0.0.99	example.org
e67796
+192.0.0.100	example.org
e67796
+192.0.0.101	example.org
e67796
+192.0.0.102	example.org
e67796
+192.0.0.103	example.org
e67796
+192.0.0.104	example.org
e67796
+192.0.0.105	example.org
e67796
+192.0.0.106	example.org
e67796
+192.0.0.107	example.org
e67796
+192.0.0.108	example.org
e67796
+192.0.0.109	example.org
e67796
+192.0.0.110	example.org
e67796
+192.0.0.111	example.org
e67796
+192.0.0.112	example.org
e67796
+192.0.0.113	example.org
e67796
+192.0.0.114	example.org
e67796
+192.0.0.115	example.org
e67796
+192.0.0.116	example.org
e67796
+192.0.0.117	example.org
e67796
+192.0.0.118	example.org
e67796
+192.0.0.119	example.org
e67796
+192.0.0.120	example.org
e67796
+192.0.0.121	example.org
e67796
+192.0.0.122	example.org
e67796
+192.0.0.123	example.org
e67796
+192.0.0.124	example.org
e67796
+192.0.0.125	example.org
e67796
+192.0.0.126	example.org
e67796
+192.0.0.127	example.org
e67796
+192.0.0.128	example.org
e67796
+192.0.0.129	example.org
e67796
+192.0.0.130	example.org
e67796
+192.0.0.131	example.org
e67796
+192.0.0.132	example.org
e67796
+192.0.0.133	example.org
e67796
+192.0.0.134	example.org
e67796
+192.0.0.135	example.org
e67796
+192.0.0.136	example.org
e67796
+192.0.0.137	example.org
e67796
+192.0.0.138	example.org
e67796
+192.0.0.139	example.org
e67796
+192.0.0.140	example.org
e67796
+192.0.0.141	example.org
e67796
+192.0.0.142	example.org
e67796
+192.0.0.143	example.org
e67796
+192.0.0.144	example.org
e67796
+192.0.0.145	example.org
e67796
+192.0.0.146	example.org
e67796
+192.0.0.147	example.org
e67796
+192.0.0.148	example.org
e67796
+192.0.0.149	example.org
e67796
+192.0.0.150	example.org
e67796
+192.0.0.151	example.org
e67796
+192.0.0.152	example.org
e67796
+192.0.0.153	example.org
e67796
+192.0.0.154	example.org
e67796
+192.0.0.155	example.org
e67796
+192.0.0.156	example.org
e67796
+192.0.0.157	example.org
e67796
+192.0.0.158	example.org
e67796
+192.0.0.159	example.org
e67796
+192.0.0.160	example.org
e67796
+192.0.0.161	example.org
e67796
+192.0.0.162	example.org
e67796
+192.0.0.163	example.org
e67796
+192.0.0.164	example.org
e67796
+192.0.0.165	example.org
e67796
+192.0.0.166	example.org
e67796
+192.0.0.167	example.org
e67796
+192.0.0.168	example.org
e67796
+192.0.0.169	example.org
e67796
+192.0.0.170	example.org
e67796
+192.0.0.171	example.org
e67796
+192.0.0.172	example.org
e67796
+192.0.0.173	example.org
e67796
+192.0.0.174	example.org
e67796
+192.0.0.175	example.org
e67796
+192.0.0.176	example.org
e67796
+192.0.0.177	example.org
e67796
+192.0.0.178	example.org
e67796
+192.0.0.179	example.org
e67796
+192.0.0.180	example.org
e67796
+192.0.0.181	example.org
e67796
+192.0.0.182	example.org
e67796
+192.0.0.183	example.org
e67796
+192.0.0.184	example.org
e67796
+192.0.0.185	example.org
e67796
+192.0.0.186	example.org
e67796
+192.0.0.187	example.org
e67796
+192.0.0.188	example.org
e67796
+192.0.0.189	example.org
e67796
+192.0.0.190	example.org
e67796
+192.0.0.191	example.org
e67796
+192.0.0.192	example.org
e67796
+192.0.0.193	example.org
e67796
+192.0.0.194	example.org
e67796
+192.0.0.195	example.org
e67796
+192.0.0.196	example.org
e67796
+192.0.0.197	example.org
e67796
+192.0.0.198	example.org
e67796
+192.0.0.199	example.org
e67796
+192.0.0.200	example.org
e67796
+192.0.0.201	example.org
e67796
+192.0.0.202	example.org
e67796
+192.0.0.203	example.org
e67796
+192.0.0.204	example.org
e67796
+192.0.0.205	example.org
e67796
+192.0.0.206	example.org
e67796
+192.0.0.207	example.org
e67796
+192.0.0.208	example.org
e67796
+192.0.0.209	example.org
e67796
+192.0.0.210	example.org
e67796
+192.0.0.211	example.org
e67796
+192.0.0.212	example.org
e67796
+192.0.0.213	example.org
e67796
+192.0.0.214	example.org
e67796
+192.0.0.215	example.org
e67796
+192.0.0.216	example.org
e67796
+192.0.0.217	example.org
e67796
+192.0.0.218	example.org
e67796
+192.0.0.219	example.org
e67796
+192.0.0.220	example.org
e67796
+192.0.0.221	example.org
e67796
+192.0.0.222	example.org
e67796
+192.0.0.223	example.org
e67796
+192.0.0.224	example.org
e67796
+192.0.0.225	example.org
e67796
+192.0.0.226	example.org
e67796
+192.0.0.227	example.org
e67796
+192.0.0.228	example.org
e67796
+192.0.0.229	example.org
e67796
+192.0.0.230	example.org
e67796
+192.0.0.231	example.org
e67796
+192.0.0.232	example.org
e67796
+192.0.0.233	example.org
e67796
+192.0.0.234	example.org
e67796
+192.0.0.235	example.org
e67796
+192.0.0.236	example.org
e67796
+192.0.0.237	example.org
e67796
+192.0.0.238	example.org
e67796
+192.0.0.239	example.org
e67796
+192.0.0.240	example.org
e67796
+192.0.0.241	example.org
e67796
+192.0.0.242	example.org
e67796
+192.0.0.243	example.org
e67796
+192.0.0.244	example.org
e67796
+192.0.0.245	example.org
e67796
+192.0.0.246	example.org
e67796
+192.0.0.247	example.org
e67796
+192.0.0.248	example.org
e67796
+192.0.0.249	example.org
e67796
+192.0.0.250	example.org
e67796
+192.0.0.251	example.org
e67796
+192.0.0.252	example.org
e67796
+192.0.0.253	example.org
e67796
+192.0.0.254	example.org
e67796
+192.0.1.1	example.org
e67796
+192.0.1.2	example.org
e67796
+192.0.1.3	example.org
e67796
+192.0.1.4	example.org
e67796
+192.0.1.5	example.org
e67796
+192.0.1.6	example.org
e67796
+192.0.1.7	example.org
e67796
+192.0.1.8	example.org
e67796
+192.0.1.9	example.org
e67796
+192.0.1.10	example.org
e67796
+192.0.1.11	example.org
e67796
+192.0.1.12	example.org
e67796
+192.0.1.13	example.org
e67796
+192.0.1.14	example.org
e67796
+192.0.1.15	example.org
e67796
+192.0.1.16	example.org
e67796
+192.0.1.17	example.org
e67796
+192.0.1.18	example.org
e67796
+192.0.1.19	example.org
e67796
+192.0.1.20	example.org
e67796
+192.0.1.21	example.org
e67796
+192.0.1.22	example.org
e67796
+192.0.1.23	example.org
e67796
+192.0.1.24	example.org
e67796
+192.0.1.25	example.org
e67796
+192.0.1.26	example.org
e67796
+192.0.1.27	example.org
e67796
+192.0.1.28	example.org
e67796
+192.0.1.29	example.org
e67796
+192.0.1.30	example.org
e67796
+192.0.1.31	example.org
e67796
+192.0.1.32	example.org
e67796
+192.0.1.33	example.org
e67796
+192.0.1.34	example.org
e67796
+192.0.1.35	example.org
e67796
+192.0.1.36	example.org
e67796
+192.0.1.37	example.org
e67796
+192.0.1.38	example.org
e67796
+192.0.1.39	example.org
e67796
+192.0.1.40	example.org
e67796
+192.0.1.41	example.org
e67796
+192.0.1.42	example.org
e67796
+192.0.1.43	example.org
e67796
+192.0.1.44	example.org
e67796
+192.0.1.45	example.org
e67796
+192.0.1.46	example.org
e67796
+192.0.1.47	example.org
e67796
+192.0.1.48	example.org
e67796
+192.0.1.49	example.org
e67796
+192.0.1.50	example.org
e67796
+192.0.1.51	example.org
e67796
+192.0.1.52	example.org
e67796
+192.0.1.53	example.org
e67796
+192.0.1.54	example.org
e67796
+192.0.1.55	example.org
e67796
+192.0.1.56	example.org
e67796
+192.0.1.57	example.org
e67796
+192.0.1.58	example.org
e67796
+192.0.1.59	example.org
e67796
+192.0.1.60	example.org
e67796
+192.0.1.61	example.org
e67796
+192.0.1.62	example.org
e67796
+192.0.1.63	example.org
e67796
+192.0.1.64	example.org
e67796
+192.0.1.65	example.org
e67796
+192.0.1.66	example.org
e67796
+192.0.1.67	example.org
e67796
+192.0.1.68	example.org
e67796
+192.0.1.69	example.org
e67796
+192.0.1.70	example.org
e67796
+192.0.1.71	example.org
e67796
+192.0.1.72	example.org
e67796
+192.0.1.73	example.org
e67796
+192.0.1.74	example.org
e67796
+192.0.1.75	example.org
e67796
+192.0.1.76	example.org
e67796
+192.0.1.77	example.org
e67796
+192.0.1.78	example.org
e67796
+192.0.1.79	example.org
e67796
+192.0.1.80	example.org
e67796
+192.0.1.81	example.org
e67796
+192.0.1.82	example.org
e67796
+192.0.1.83	example.org
e67796
+192.0.1.84	example.org
e67796
+192.0.1.85	example.org
e67796
+192.0.1.86	example.org
e67796
+192.0.1.87	example.org
e67796
+192.0.1.88	example.org
e67796
+192.0.1.89	example.org
e67796
+192.0.1.90	example.org
e67796
+192.0.1.91	example.org
e67796
+192.0.1.92	example.org
e67796
+192.0.1.93	example.org
e67796
+192.0.1.94	example.org
e67796
+192.0.1.95	example.org
e67796
+192.0.1.96	example.org
e67796
+192.0.1.97	example.org
e67796
+192.0.1.98	example.org
e67796
+192.0.1.99	example.org
e67796
+192.0.1.100	example.org
e67796
+192.0.1.101	example.org
e67796
+192.0.1.102	example.org
e67796
+192.0.1.103	example.org
e67796
+192.0.1.104	example.org
e67796
+192.0.1.105	example.org
e67796
+192.0.1.106	example.org
e67796
+192.0.1.107	example.org
e67796
+192.0.1.108	example.org
e67796
+192.0.1.109	example.org
e67796
+192.0.1.110	example.org
e67796
+192.0.1.111	example.org
e67796
+192.0.1.112	example.org
e67796
+192.0.1.113	example.org
e67796
+192.0.1.114	example.org
e67796
+192.0.1.115	example.org
e67796
+192.0.1.116	example.org
e67796
+192.0.1.117	example.org
e67796
+192.0.1.118	example.org
e67796
+192.0.1.119	example.org
e67796
+192.0.1.120	example.org
e67796
+192.0.1.121	example.org
e67796
+192.0.1.122	example.org
e67796
+192.0.1.123	example.org
e67796
+192.0.1.124	example.org
e67796
+192.0.1.125	example.org
e67796
+192.0.1.126	example.org
e67796
+192.0.1.127	example.org
e67796
+192.0.1.128	example.org
e67796
+192.0.1.129	example.org
e67796
+192.0.1.130	example.org
e67796
+192.0.1.131	example.org
e67796
+192.0.1.132	example.org
e67796
+192.0.1.133	example.org
e67796
+192.0.1.134	example.org
e67796
+192.0.1.135	example.org
e67796
+192.0.1.136	example.org
e67796
+192.0.1.137	example.org
e67796
+192.0.1.138	example.org
e67796
+192.0.1.139	example.org
e67796
+192.0.1.140	example.org
e67796
+192.0.1.141	example.org
e67796
+192.0.1.142	example.org
e67796
+192.0.1.143	example.org
e67796
+192.0.1.144	example.org
e67796
+192.0.1.145	example.org
e67796
+192.0.1.146	example.org
e67796
+192.0.1.147	example.org
e67796
+192.0.1.148	example.org
e67796
+192.0.1.149	example.org
e67796
+192.0.1.150	example.org
e67796
+192.0.1.151	example.org
e67796
+192.0.1.152	example.org
e67796
+192.0.1.153	example.org
e67796
+192.0.1.154	example.org
e67796
+192.0.1.155	example.org
e67796
+192.0.1.156	example.org
e67796
+192.0.1.157	example.org
e67796
+192.0.1.158	example.org
e67796
+192.0.1.159	example.org
e67796
+192.0.1.160	example.org
e67796
+192.0.1.161	example.org
e67796
+192.0.1.162	example.org
e67796
+192.0.1.163	example.org
e67796
+192.0.1.164	example.org
e67796
+192.0.1.165	example.org
e67796
+192.0.1.166	example.org
e67796
+192.0.1.167	example.org
e67796
+192.0.1.168	example.org
e67796
+192.0.1.169	example.org
e67796
+192.0.1.170	example.org
e67796
+192.0.1.171	example.org
e67796
+192.0.1.172	example.org
e67796
+192.0.1.173	example.org
e67796
+192.0.1.174	example.org
e67796
+192.0.1.175	example.org
e67796
+192.0.1.176	example.org
e67796
+192.0.1.177	example.org
e67796
+192.0.1.178	example.org
e67796
+192.0.1.179	example.org
e67796
+192.0.1.180	example.org
e67796
+192.0.1.181	example.org
e67796
+192.0.1.182	example.org
e67796
+192.0.1.183	example.org
e67796
+192.0.1.184	example.org
e67796
+192.0.1.185	example.org
e67796
+192.0.1.186	example.org
e67796
+192.0.1.187	example.org
e67796
+192.0.1.188	example.org
e67796
+192.0.1.189	example.org
e67796
+192.0.1.190	example.org
e67796
+192.0.1.191	example.org
e67796
+192.0.1.192	example.org
e67796
+192.0.1.193	example.org
e67796
+192.0.1.194	example.org
e67796
+192.0.1.195	example.org
e67796
+192.0.1.196	example.org
e67796
+192.0.1.197	example.org
e67796
+192.0.1.198	example.org
e67796
+192.0.1.199	example.org
e67796
+192.0.1.200	example.org
e67796
+192.0.1.201	example.org
e67796
+192.0.1.202	example.org
e67796
+192.0.1.203	example.org
e67796
+192.0.1.204	example.org
e67796
+192.0.1.205	example.org
e67796
+192.0.1.206	example.org
e67796
+192.0.1.207	example.org
e67796
+192.0.1.208	example.org
e67796
+192.0.1.209	example.org
e67796
+192.0.1.210	example.org
e67796
+192.0.1.211	example.org
e67796
+192.0.1.212	example.org
e67796
+192.0.1.213	example.org
e67796
+192.0.1.214	example.org
e67796
+192.0.1.215	example.org
e67796
+192.0.1.216	example.org
e67796
+192.0.1.217	example.org
e67796
+192.0.1.218	example.org
e67796
+192.0.1.219	example.org
e67796
+192.0.1.220	example.org
e67796
+192.0.1.221	example.org
e67796
+192.0.1.222	example.org
e67796
+192.0.1.223	example.org
e67796
+192.0.1.224	example.org
e67796
+192.0.1.225	example.org
e67796
+192.0.1.226	example.org
e67796
+192.0.1.227	example.org
e67796
+192.0.1.228	example.org
e67796
+192.0.1.229	example.org
e67796
+192.0.1.230	example.org
e67796
+192.0.1.231	example.org
e67796
+192.0.1.232	example.org
e67796
+192.0.1.233	example.org
e67796
+192.0.1.234	example.org
e67796
+192.0.1.235	example.org
e67796
+192.0.1.236	example.org
e67796
+192.0.1.237	example.org
e67796
+192.0.1.238	example.org
e67796
+192.0.1.239	example.org
e67796
+192.0.1.240	example.org
e67796
+192.0.1.241	example.org
e67796
+192.0.1.242	example.org
e67796
+192.0.1.243	example.org
e67796
+192.0.1.244	example.org
e67796
+192.0.1.245	example.org
e67796
+192.0.1.246	example.org
e67796
+192.0.1.247	example.org
e67796
+192.0.1.248	example.org
e67796
+192.0.1.249	example.org
e67796
+192.0.1.250	example.org
e67796
+192.0.1.251	example.org
e67796
+192.0.1.252	example.org
e67796
+192.0.1.253	example.org
e67796
+192.0.1.254	example.org
e67796
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
e67796
index fae3dea81f19dba6..4fa963644af8b7d5 100644
e67796
--- a/sysdeps/posix/getaddrinfo.c
e67796
+++ b/sysdeps/posix/getaddrinfo.c
e67796
@@ -474,11 +474,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
e67796
 
e67796
   if (name != NULL)
e67796
     {
e67796
-      at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
e67796
-      at->family = AF_UNSPEC;
e67796
-      at->scopeid = 0;
e67796
-      at->next = NULL;
e67796
-
e67796
       if (req->ai_flags & AI_IDN)
e67796
 	{
e67796
 	  char *out;
e67796
@@ -489,13 +484,21 @@ gaih_inet (const char *name, const struct gaih_service *service,
e67796
 	  malloc_name = true;
e67796
 	}
e67796
 
e67796
-      if (__inet_aton_exact (name, (struct in_addr *) at->addr) != 0)
e67796
+      uint32_t addr[4];
e67796
+      if (__inet_aton_exact (name, (struct in_addr *) addr) != 0)
e67796
 	{
e67796
+	  at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used);
e67796
+	  at->scopeid = 0;
e67796
+	  at->next = NULL;
e67796
+
e67796
 	  if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
e67796
-	    at->family = AF_INET;
e67796
+	    {
e67796
+	      memcpy (at->addr, addr, sizeof (at->addr));
e67796
+	      at->family = AF_INET;
e67796
+	    }
e67796
 	  else if (req->ai_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED))
e67796
 	    {
e67796
-	      at->addr[3] = at->addr[0];
e67796
+	      at->addr[3] = addr[0];
e67796
 	      at->addr[2] = htonl (0xffff);
e67796
 	      at->addr[1] = 0;
e67796
 	      at->addr[0] = 0;
e67796
@@ -509,49 +512,62 @@ gaih_inet (const char *name, const struct gaih_service *service,
e67796
 
e67796
 	  if (req->ai_flags & AI_CANONNAME)
e67796
 	    canon = name;
e67796
+
e67796
+	  goto process_list;
e67796
 	}
e67796
-      else if (at->family == AF_UNSPEC)
e67796
+
e67796
+      char *scope_delim = strchr (name, SCOPE_DELIMITER);
e67796
+      int e;
e67796
+
e67796
+      if (scope_delim == NULL)
e67796
+	e = inet_pton (AF_INET6, name, addr);
e67796
+      else
e67796
+	e = __inet_pton_length (AF_INET6, name, scope_delim - name, addr);
e67796
+
e67796
+      if (e > 0)
e67796
 	{
e67796
-	  char *scope_delim = strchr (name, SCOPE_DELIMITER);
e67796
-	  int e;
e67796
-	  if (scope_delim == NULL)
e67796
-	    e = inet_pton (AF_INET6, name, at->addr);
e67796
+	  at = alloca_account (sizeof (struct gaih_addrtuple),
e67796
+			       alloca_used);
e67796
+	  at->scopeid = 0;
e67796
+	  at->next = NULL;
e67796
+
e67796
+	  if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
e67796
+	    {
e67796
+	      memcpy (at->addr, addr, sizeof (at->addr));
e67796
+	      at->family = AF_INET6;
e67796
+	    }
e67796
+	  else if (req->ai_family == AF_INET
e67796
+		   && IN6_IS_ADDR_V4MAPPED (addr))
e67796
+	    {
e67796
+	      at->addr[0] = addr[3];
e67796
+	      at->addr[1] = addr[1];
e67796
+	      at->addr[2] = addr[2];
e67796
+	      at->addr[3] = addr[3];
e67796
+	      at->family = AF_INET;
e67796
+	    }
e67796
 	  else
e67796
-	    e = __inet_pton_length (AF_INET6, name, scope_delim - name,
e67796
-				    at->addr);
e67796
-	  if (e > 0)
e67796
 	    {
e67796
-	      if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)
e67796
-		at->family = AF_INET6;
e67796
-	      else if (req->ai_family == AF_INET
e67796
-		       && IN6_IS_ADDR_V4MAPPED (at->addr))
e67796
-		{
e67796
-		  at->addr[0] = at->addr[3];
e67796
-		  at->family = AF_INET;
e67796
-		}
e67796
-	      else
e67796
-		{
e67796
-		  result = -EAI_ADDRFAMILY;
e67796
-		  goto free_and_return;
e67796
-		}
e67796
-
e67796
-	      if (scope_delim != NULL
e67796
-		  && __inet6_scopeid_pton ((struct in6_addr *) at->addr,
e67796
-					   scope_delim + 1,
e67796
-					   &at->scopeid) != 0)
e67796
-		{
e67796
-		  result = -EAI_NONAME;
e67796
-		  goto free_and_return;
e67796
-		}
e67796
+	      result = -EAI_ADDRFAMILY;
e67796
+	      goto free_and_return;
e67796
+	    }
e67796
 
e67796
-	      if (req->ai_flags & AI_CANONNAME)
e67796
-		canon = name;
e67796
+	  if (scope_delim != NULL
e67796
+	      && __inet6_scopeid_pton ((struct in6_addr *) at->addr,
e67796
+				       scope_delim + 1,
e67796
+				       &at->scopeid) != 0)
e67796
+	    {
e67796
+	      result = -EAI_NONAME;
e67796
+	      goto free_and_return;
e67796
 	    }
e67796
+
e67796
+	  if (req->ai_flags & AI_CANONNAME)
e67796
+	    canon = name;
e67796
+
e67796
+	  goto process_list;
e67796
 	}
e67796
 
e67796
-      if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0)
e67796
+      if ((req->ai_flags & AI_NUMERICHOST) == 0)
e67796
 	{
e67796
-	  struct gaih_addrtuple **pat = &at;
e67796
 	  int no_data = 0;
e67796
 	  int no_inet6_data = 0;
e67796
 	  service_user *nip;
e67796
@@ -560,6 +576,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
e67796
 	  int no_more;
e67796
 	  struct resolv_context *res_ctx = NULL;
e67796
 	  bool res_enable_inet6 = false;
e67796
+	  bool do_merge = false;
e67796
 
e67796
 	  /* If we do not have to look for IPv6 addresses or the canonical
e67796
 	     name, use the simple, old functions, which do not support
e67796
@@ -596,7 +613,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
e67796
 			  result = -EAI_MEMORY;
e67796
 			  goto free_and_return;
e67796
 			}
e67796
-		      *pat = addrmem;
e67796
+		      at = addrmem;
e67796
 		    }
e67796
 		  else
e67796
 		    {
e67796
@@ -649,6 +666,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
e67796
 		    }
e67796
 
e67796
 		  struct gaih_addrtuple *addrfree = addrmem;
e67796
+		  struct gaih_addrtuple **pat = &at;
e67796
+
e67796
 		  for (int i = 0; i < air->naddrs; ++i)
e67796
 		    {
e67796
 		      socklen_t size = (air->family[i] == AF_INET
e67796
@@ -712,12 +731,6 @@ gaih_inet (const char *name, const struct gaih_service *service,
e67796
 
e67796
 		  free (air);
e67796
 
e67796
-		  if (at->family == AF_UNSPEC)
e67796
-		    {
e67796
-		      result = -EAI_NONAME;
e67796
-		      goto free_and_return;
e67796
-		    }
e67796
-
e67796
 		  goto process_list;
e67796
 		}
e67796
 	      else if (err == 0)
e67796
@@ -756,6 +769,22 @@ gaih_inet (const char *name, const struct gaih_service *service,
e67796
 
e67796
 	  while (!no_more)
e67796
 	    {
e67796
+	      /* Always start afresh; continue should discard previous results
e67796
+		 and the hosts database does not support merge.  */
e67796
+	      at = NULL;
e67796
+	      free (canonbuf);
e67796
+	      free (addrmem);
e67796
+	      canon = canonbuf = NULL;
e67796
+	      addrmem = NULL;
e67796
+	      got_ipv6 = false;
e67796
+
e67796
+	      if (do_merge)
e67796
+		{
e67796
+		  __set_h_errno (NETDB_INTERNAL);
e67796
+		  __set_errno (EBUSY);
e67796
+		  break;
e67796
+		}
e67796
+
e67796
 	      no_data = 0;
e67796
 	      nss_gethostbyname4_r fct4 = NULL;
e67796
 
e67796
@@ -768,12 +797,14 @@ gaih_inet (const char *name, const struct gaih_service *service,
e67796
 		{
e67796
 		  while (1)
e67796
 		    {
e67796
-		      status = DL_CALL_FCT (fct4, (name, pat,
e67796
+		      status = DL_CALL_FCT (fct4, (name, &at,
e67796
 						   tmpbuf->data, tmpbuf->length,
e67796
 						   &errno, &h_errno,
e67796
 						   NULL));
e67796
 		      if (status == NSS_STATUS_SUCCESS)
e67796
 			break;
e67796
+		      /* gethostbyname4_r may write into AT, so reset it.  */
e67796
+		      at = NULL;
e67796
 		      if (status != NSS_STATUS_TRYAGAIN
e67796
 			  || errno != ERANGE || h_errno != NETDB_INTERNAL)
e67796
 			{
e67796
@@ -800,7 +831,9 @@ gaih_inet (const char *name, const struct gaih_service *service,
e67796
 		      no_data = 1;
e67796
 
e67796
 		      if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL)
e67796
-			canon = (*pat)->name;
e67796
+			canon = at->name;
e67796
+
e67796
+		      struct gaih_addrtuple **pat = &at;
e67796
 
e67796
 		      while (*pat != NULL)
e67796
 			{
e67796
@@ -852,6 +885,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
e67796
 
e67796
 		  if (fct != NULL)
e67796
 		    {
e67796
+		      struct gaih_addrtuple **pat = &at;
e67796
+
e67796
 		      if (req->ai_family == AF_INET6
e67796
 			  || req->ai_family == AF_UNSPEC)
e67796
 			{
e67796
@@ -927,6 +962,10 @@ gaih_inet (const char *name, const struct gaih_service *service,
e67796
 	      if (nss_next_action (nip, status) == NSS_ACTION_RETURN)
e67796
 		break;
e67796
 
e67796
+	      /* The hosts database does not support MERGE.  */
e67796
+	      if (nss_next_action (nip, status) == NSS_ACTION_MERGE)
e67796
+		do_merge = true;
e67796
+
e67796
 	      if (nip->next == NULL)
e67796
 		no_more = -1;
e67796
 	      else
e67796
@@ -960,7 +999,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
e67796
 	}
e67796
 
e67796
     process_list:
e67796
-      if (at->family == AF_UNSPEC)
e67796
+      if (at == NULL)
e67796
 	{
e67796
 	  result = -EAI_NONAME;
e67796
 	  goto free_and_return;