From patchwork Fri Mar 20 20:41:37 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 132110 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id BACC84C900E8 for ; Fri, 20 Mar 2026 20:45:41 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org BACC84C900E8 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=N4qzchvr X-Original-To: libc-alpha@sourceware.org Delivered-To: libc-alpha@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id 1B22A4C900DA for ; Fri, 20 Mar 2026 20:41:43 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 1B22A4C900DA Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 1B22A4C900DA Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039308; cv=none; b=lECS9uV5YCEC0QNDuwiox1rJT8Llb9xBOxtWtuOt58ELV2I11dn6UhvXz/Q+2wHki0w0fk1BqBNO3eDuIw7MHZctutGOLjt214vB+0KcAXxl3GpUkFyMgTbxA9zOWmF1G1MjUCRzSkvDNugt8ruXDcQRnub8pf2OqHDFk6BTtp0= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1774039308; c=relaxed/simple; bh=jmvs47ZhXaea0lKeWQ+U5mdLjyMCSW08lzpBRaimZOs=; h=DKIM-Signature:From:To:Subject:Message-ID:Date:MIME-Version; b=KkhfLsjp+GEKVJ36QJM7BLL2F3Sfd2a2y5t8+u1Z7KYGbku0BtPWLimZONN+4SqhJTPXEWjBuC7uFR5yrIeDw0ROt5VcIKCHqXZ0FlbE3tdu98cPc83YBK+n5G2UK1x8vhxRRrXQb9fLM9SHFKNxxqJm5aArPQ9Cgec/3jHymKo= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1B22A4C900DA DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1774039302; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=ed2JHbdSh17E6kKEI+Kq6rEeIglkgth1n3BtcRKCECI=; b=N4qzchvrYjUxrCrKpmXiyWjUbkVtVpZRXcImvmItEeV6XjD0AnbLZoIFXBlSYcfy67TdHF UW16CR4qvFOBQeVt+7YIugdrwUa6+hrmWIergTeDrf5irpI9SanUcRQNvK1owQfa+IVh0p 4l4qjrHhV3v5lBhz+6thQwI+H/+SxAA= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-453-VdWUIDeqMf6delme95-9pw-1; Fri, 20 Mar 2026 16:41:41 -0400 X-MC-Unique: VdWUIDeqMf6delme95-9pw-1 X-Mimecast-MFC-AGG-ID: VdWUIDeqMf6delme95-9pw_1774039300 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 6F90E1956048 for ; Fri, 20 Mar 2026 20:41:40 +0000 (UTC) Received: from fweimer-oldenburg.csb.redhat.com (unknown [10.45.224.63]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id B6BBD1953944 for ; Fri, 20 Mar 2026 20:41:39 +0000 (UTC) From: Florian Weimer To: libc-alpha@sourceware.org Subject: [PATCH v2 04/23] nss: Add negative lookup test In-Reply-To: Message-ID: <6f3039be2fe4e959a64c69ad177b4a70d539eda1.1774037705.git.fweimer@redhat.com> References: X-From-Line: 6f3039be2fe4e959a64c69ad177b4a70d539eda1 Mon Sep 17 00:00:00 2001 Date: Fri, 20 Mar 2026 21:41:37 +0100 User-Agent: Gnus/5.13 (Gnus v5.13) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: W3XRofMmm7ek4lGKOP6edMzt8g5kpi3eHqLcG_T3iUk_1774039300 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-9.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, PROLO_LEO1, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_PASS, SPF_NONE, TXREP, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: libc-alpha@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Libc-alpha mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libc-alpha-bounces~patchwork=sourceware.org@sourceware.org --- nss/Makefile | 3 + nss/tst-nss-does-not-exist.cc | 210 ++++++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+) create mode 100644 nss/tst-nss-does-not-exist.cc Reviewed-by: Carlos O'Donell diff --git a/nss/Makefile b/nss/Makefile index 1c48bd0876..42d28cf40a 100644 --- a/nss/Makefile +++ b/nss/Makefile @@ -324,6 +324,7 @@ tests := \ tst-gethnm \ tst-getpw \ tst-gshadow \ + tst-nss-does-not-exist \ tst-nss-getpwent \ tst-nss-hash \ tst-nss-malloc-failure-getlogin_r \ @@ -537,3 +538,5 @@ LDFLAGS-tst-nss-test4 = -Wl,--disable-new-dtags LDFLAGS-tst-nss-test5 = -Wl,--disable-new-dtags LDFLAGS-tst-nss-test_errno = -Wl,--disable-new-dtags LDFLAGS-tst-nss-test_gai_hv2_canonname = -Wl,--disable-new-dtags + +LDLIBS-tst-nss-does-not-exist = -lstdc++ diff --git a/nss/tst-nss-does-not-exist.cc b/nss/tst-nss-does-not-exist.cc new file mode 100644 index 0000000000..72f7c635d8 --- /dev/null +++ b/nss/tst-nss-does-not-exist.cc @@ -0,0 +1,210 @@ +/* Verify that lookup failures have the expected error behavior. + Copyright (C) 2026 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +/* This test case triggers lookup failures for most NSS functions + (both allocated and *_r variants). It is written in C++ so that + the required types can be inferred from the lookup functions + themselves. */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static const char non_existing_name[] + = "this-name-does-not-exist-in-the-system"; + +/* True if *_r lookup functions for type T use an extra h_errno + argument. */ +template constexpr bool uses_h_errno = + std::is_same_v || std::is_same_v ; + +/* Call a *_r NSS function that produces an NSS lookup of result T + repeatedly until it does not return ERANGE. The final return value + is written to the ret member, and the pointer to the result + structure to the result member. The result can be nullptr for a + negative lookup result. */ +template +struct erange_wrapper +{ + int ret; + T *result; + + template + erange_wrapper (Impl impl, Args&&... args) + { + buffer.resize (32); + result = (T *) -1; + while (true) + { + h_errno = 0; + int herrno = 0; + if constexpr (uses_h_errno ) + ret = impl (std::forward(args)..., + &storage, buffer.data (), buffer.size (), &result, + &herrno); + else + { + /* No h_errno pointer argument. Pretend that failures + are always due to NETDB_INTERNAL. */ + ret = impl (std::forward(args)..., + &storage, buffer.data (), buffer.size (), &result); + herrno = NETDB_INTERNAL; + } + if (herrno == NETDB_INTERNAL && ret == ERANGE) + { + buffer.resize (buffer.size () * 2); + TEST_VERIFY (buffer.size () > 0); + } + else + break; + } + } + + /* Verify that ret and result denote a negative lookup result. */ + void expected_negative () + { + TEST_COMPARE (ret, 0); + TEST_VERIFY (result == nullptr); + } + +private: + T storage; + std::vector buffer; +}; + +/* Verify that looking up non_existing_name fails for the non-_r and _r + function variants. */ +template +static void +check_missing_name (Lookup lookup, LookupR lookup_r, Args&&... args) +{ + verbose_printf ("info: name lookup: %s\n", + strchr (__PRETTY_FUNCTION__, '[')); + errno = 0; + auto r = lookup (non_existing_name, std::forward(args)...); + TEST_VERIFY (r == nullptr); + TEST_COMPARE (errno, 0); + using nss_type = typename std::remove_reference ::type; + erange_wrapper (lookup_r, non_existing_name, + std::forward(args)...).expected_negative (); +} + +/* Find an ID that results in a lookup failure using the non-_r function, + and then verify that it also fails with the _r function. ID_MEMBER + is the pointer to the struct member that contains the looked-up ID. */ +template +static void +find_missing_id (const char *type_name, Lookup lookup, LookupR lookup_r, + Member id_member, Args&&... args) +{ + verbose_printf ("info: ID lookup for %s: %s\n", + type_name, strchr (__PRETTY_FUNCTION__, '[')); + using nss_type = typename std::remove_reference + (args)...))>::type; + using id_type = decltype(nss_type{}.*id_member); + for (id_type i = 0; i < 65536; ++i) + { + verbose_printf ("info: trying %lld\n", (long long int) i); + errno = 0; + nss_type *r = lookup (i, std::forward(args)...); + if (r == nullptr) + { + TEST_COMPARE (errno, 0); + printf ("info: first missing %s: %lld\n", type_name, + (long long int) i); + + erange_wrapper (lookup_r, i, std::forward(args)...) + .expected_negative (); + return; + } + TEST_COMPARE (r->*id_member, i); + } + printf ("warning: could not find an undefined ID for %s\n", type_name); +} + +static void +checks (void *closure) +{ + check_missing_name (getpwnam, getpwnam_r); + find_missing_id ("passwd", getpwuid, getpwuid_r, &passwd::pw_uid); + + check_missing_name (getgrnam, getgrnam_r); + find_missing_id ("group", getgrgid, getgrgid_r, &group::gr_gid); + + check_missing_name (getprotobyname, getprotobyname_r); + find_missing_id ("protoent", getprotobynumber, getprotobynumber_r, + &protoent::p_proto); + + check_missing_name (getservbyname, getservbyname_r, "tcp"); + find_missing_id ("servent", getservbyport, getservbyport_r, + &servent::s_port, "tcp"); + + check_missing_name (getaliasbyname, getaliasbyname_r); + + check_missing_name (getrpcbyname, getrpcbyname_r); + find_missing_id ("rpcent", getrpcbynumber, getrpcbynumber_r, + &rpcent::r_number); + + check_missing_name (gethostbyname, gethostbyname_r); + check_missing_name (gethostbyname2, gethostbyname2_r, AF_INET); + + check_missing_name (getnetbyname, getnetbyname_r); + + /* Exceptional case: no buffer argument, no ERANGE protocol. */ + { + errno = 0; + TEST_VERIFY (ether_aton (non_existing_name) == nullptr); + TEST_COMPARE (errno, 0); + struct ether_addr addr; + TEST_VERIFY (ether_aton_r (non_existing_name, &addr) == nullptr); + TEST_COMPARE (errno, 0); + } +} + +static int +do_test (void) +{ + /* First test the system default. */ + puts ("info: testing system default"); + support_isolate_in_subprocess (checks, nullptr); + + /* Then test the files module specifically. */ + puts ("info: testing files module"); +#define DEFINE_DATABASE(db) __nss_configure_lookup (#db, "files"); +#include "databases.def" +#undef DEFINE_DATABASE + support_isolate_in_subprocess (checks, nullptr); + + return 0; +} + +#include