[libc-commits] [libc] 14f097e - [libc] Add getpwnam and getpwuid entrypoints (#221169)

via libc-commits libc-commits at lists.llvm.org
Fri Sep 4 08:00:56 PDT 2026


Author: Jeff Bailey
Date: 2026-09-04T16:00:51+01:00
New Revision: 14f097ec3f2bef83e852d9ded7b117fcf2f4e103

URL: https://github.com/llvm/llvm-project/commit/14f097ec3f2bef83e852d9ded7b117fcf2f4e103
DIFF: https://github.com/llvm/llvm-project/commit/14f097ec3f2bef83e852d9ded7b117fcf2f4e103.diff

LOG: [libc] Add getpwnam and getpwuid entrypoints (#221169)

Added non-reentrant getpwnam and getpwuid functions using the shared
process-global buffer.

* Implemented getpwnam and getpwuid entrypoints
* Added non-reentrant find_by_name and find_by_uid lookups
* Added function specifications to include/pwd.yaml
* Registered entrypoints in config/linux/*/entrypoints.txt
* Added unit tests in libc/test/src/pwd/getpwnam_test.cpp and
libc/test/src/pwd/getpwuid_test.cpp

Assisted-by: Automated tooling, human reviewed.

Added: 
    libc/src/pwd/getpwnam.cpp
    libc/src/pwd/getpwnam.h
    libc/src/pwd/getpwuid.cpp
    libc/src/pwd/getpwuid.h
    libc/test/src/pwd/getpwnam_test.cpp
    libc/test/src/pwd/getpwuid_test.cpp

Modified: 
    libc/config/linux/aarch64/entrypoints.txt
    libc/config/linux/arm/entrypoints.txt
    libc/config/linux/i386/entrypoints.txt
    libc/config/linux/riscv/entrypoints.txt
    libc/config/linux/x86_64/entrypoints.txt
    libc/include/pwd.yaml
    libc/src/pwd/CMakeLists.txt
    libc/src/pwd/pwd_utils.cpp
    libc/src/pwd/pwd_utils.h
    libc/test/src/pwd/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index cf6a6c2815a7b..cc0cb0eb56d12 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -48,7 +48,9 @@ set(TARGET_LIBC_ENTRYPOINTS
     # pwd.h entrypoints
     libc.src.pwd.endpwent
     libc.src.pwd.getpwent
+    libc.src.pwd.getpwnam
     libc.src.pwd.getpwnam_r
+    libc.src.pwd.getpwuid
     libc.src.pwd.getpwuid_r
     libc.src.pwd.setpwent
 

diff  --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt
index 79b674fd99e9f..7d2daae7a89c7 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -36,7 +36,9 @@ set(TARGET_LIBC_ENTRYPOINTS
     # pwd.h entrypoints
     libc.src.pwd.endpwent
     libc.src.pwd.getpwent
+    libc.src.pwd.getpwnam
     libc.src.pwd.getpwnam_r
+    libc.src.pwd.getpwuid
     libc.src.pwd.getpwuid_r
     libc.src.pwd.setpwent
 

diff  --git a/libc/config/linux/i386/entrypoints.txt b/libc/config/linux/i386/entrypoints.txt
index 1b84b0e7a0519..4766ea1522cae 100644
--- a/libc/config/linux/i386/entrypoints.txt
+++ b/libc/config/linux/i386/entrypoints.txt
@@ -5,7 +5,9 @@ set(TARGET_LIBC_ENTRYPOINTS
   # pwd.h entrypoints
   libc.src.pwd.endpwent
   libc.src.pwd.getpwent
+  libc.src.pwd.getpwnam
   libc.src.pwd.getpwnam_r
+  libc.src.pwd.getpwuid
   libc.src.pwd.getpwuid_r
   libc.src.pwd.setpwent
 )

diff  --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 9272a670d35d6..f574a225c092f 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -67,7 +67,9 @@ set(TARGET_LIBC_ENTRYPOINTS
     # pwd.h entrypoints
     libc.src.pwd.endpwent
     libc.src.pwd.getpwent
+    libc.src.pwd.getpwnam
     libc.src.pwd.getpwnam_r
+    libc.src.pwd.getpwuid
     libc.src.pwd.getpwuid_r
     libc.src.pwd.setpwent
 

diff  --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 28f2b9a480ef3..4de6a291fef66 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -67,7 +67,9 @@ set(TARGET_LIBC_ENTRYPOINTS
     # pwd.h entrypoints
     libc.src.pwd.endpwent
     libc.src.pwd.getpwent
+    libc.src.pwd.getpwnam
     libc.src.pwd.getpwnam_r
+    libc.src.pwd.getpwuid
     libc.src.pwd.getpwuid_r
     libc.src.pwd.setpwent
 

diff  --git a/libc/include/pwd.yaml b/libc/include/pwd.yaml
index ef3656f3a1042..9301307d22d3a 100644
--- a/libc/include/pwd.yaml
+++ b/libc/include/pwd.yaml
@@ -24,6 +24,12 @@ functions:
       - posix
     return_type: void
     arguments: []
+  - name: getpwnam
+    standards:
+      - posix
+    return_type: struct passwd *
+    arguments:
+      - type: const char *
   - name: getpwnam_r
     standards:
       - posix
@@ -34,6 +40,12 @@ functions:
       - type: char *
       - type: size_t
       - type: struct passwd **
+  - name: getpwuid
+    standards:
+      - posix
+    return_type: struct passwd *
+    arguments:
+      - type: uid_t
   - name: getpwuid_r
     standards:
       - posix

diff  --git a/libc/src/pwd/CMakeLists.txt b/libc/src/pwd/CMakeLists.txt
index 0a5aaca358cd0..c2b86dab45db8 100644
--- a/libc/src/pwd/CMakeLists.txt
+++ b/libc/src/pwd/CMakeLists.txt
@@ -42,6 +42,21 @@ add_entrypoint_object(
     .pwd_utils
 )
 
+add_entrypoint_object(
+  getpwnam
+  SRCS
+    getpwnam.cpp
+  HDRS
+    getpwnam.h
+  DEPENDS
+    libc.hdr.types.struct_passwd
+    libc.src.errno.errno
+    libc.src.__support.common
+    libc.src.__support.macros.config
+    libc.src.__support.macros.null_check
+    .pwd_utils
+)
+
 add_entrypoint_object(
   getpwnam_r
   SRCS
@@ -59,6 +74,21 @@ add_entrypoint_object(
     .pwd_utils
 )
 
+add_entrypoint_object(
+  getpwuid
+  SRCS
+    getpwuid.cpp
+  HDRS
+    getpwuid.h
+  DEPENDS
+    libc.hdr.types.struct_passwd
+    libc.hdr.types.uid_t
+    libc.src.errno.errno
+    libc.src.__support.common
+    libc.src.__support.macros.config
+    .pwd_utils
+)
+
 add_entrypoint_object(
   getpwuid_r
   SRCS

diff  --git a/libc/src/pwd/getpwnam.cpp b/libc/src/pwd/getpwnam.cpp
new file mode 100644
index 0000000000000..d57589ced2a7b
--- /dev/null
+++ b/libc/src/pwd/getpwnam.cpp
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation of getpwnam.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/pwd/getpwnam.h"
+#include "hdr/types/struct_passwd.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/null_check.h"
+#include "src/pwd/pwd_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(struct passwd *, getpwnam, (const char *name)) {
+  LIBC_CRASH_ON_NULLPTR(name);
+
+  auto res = pwd::find_by_name(name);
+  if (!res.has_value()) {
+    libc_errno = res.error();
+    return nullptr;
+  }
+  return res.value();
+}
+
+} // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/pwd/getpwnam.h b/libc/src/pwd/getpwnam.h
new file mode 100644
index 0000000000000..3e07b6eafbcc4
--- /dev/null
+++ b/libc/src/pwd/getpwnam.h
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Header file for getpwnam function.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_PWD_GETPWNAM_H
+#define LLVM_LIBC_SRC_PWD_GETPWNAM_H
+
+#include "hdr/types/struct_passwd.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+// Searches the password database for an entry with the matching username.
+struct passwd *getpwnam(const char *name);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_PWD_GETPWNAM_H

diff  --git a/libc/src/pwd/getpwuid.cpp b/libc/src/pwd/getpwuid.cpp
new file mode 100644
index 0000000000000..61d527856ff2b
--- /dev/null
+++ b/libc/src/pwd/getpwuid.cpp
@@ -0,0 +1,32 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation of getpwuid.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/pwd/getpwuid.h"
+#include "hdr/types/struct_passwd.h"
+#include "hdr/types/uid_t.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/pwd/pwd_utils.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(struct passwd *, getpwuid, (uid_t uid)) {
+  auto res = pwd::find_by_uid(uid);
+  if (!res.has_value()) {
+    libc_errno = res.error();
+    return nullptr;
+  }
+  return res.value();
+}
+
+} // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/pwd/getpwuid.h b/libc/src/pwd/getpwuid.h
new file mode 100644
index 0000000000000..26ce10430794b
--- /dev/null
+++ b/libc/src/pwd/getpwuid.h
@@ -0,0 +1,28 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Header file for getpwuid function.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_PWD_GETPWUID_H
+#define LLVM_LIBC_SRC_PWD_GETPWUID_H
+
+#include "hdr/types/struct_passwd.h"
+#include "hdr/types/uid_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+// Searches the password database for an entry with the matching user ID.
+struct passwd *getpwuid(uid_t uid);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_PWD_GETPWUID_H

diff  --git a/libc/src/pwd/pwd_utils.cpp b/libc/src/pwd/pwd_utils.cpp
index cc10a21bef021..c9134d3f4c962 100644
--- a/libc/src/pwd/pwd_utils.cpp
+++ b/libc/src/pwd/pwd_utils.cpp
@@ -93,5 +93,25 @@ ErrorOr<bool> find_by_uid(uid_t uid, struct passwd *pwd, cpp::span<char> buffer,
   return local_db.lookup(matcher, pwd, buffer);
 }
 
+ErrorOr<struct passwd *> find_by_name(cpp::string_view name) {
+  auto res = find_by_name(name, &pwd_entry, line_buffer);
+  if (!res.has_value())
+    return Error(res.error());
+  bool found = res.value();
+  if (!found)
+    return nullptr;
+  return &pwd_entry;
+}
+
+ErrorOr<struct passwd *> find_by_uid(uid_t uid) {
+  auto res = find_by_uid(uid, &pwd_entry, line_buffer);
+  if (!res.has_value())
+    return Error(res.error());
+  bool found = res.value();
+  if (!found)
+    return nullptr;
+  return &pwd_entry;
+}
+
 } // namespace pwd
 } // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/pwd/pwd_utils.h b/libc/src/pwd/pwd_utils.h
index 249de89e258d2..75c6fbe389570 100644
--- a/libc/src/pwd/pwd_utils.h
+++ b/libc/src/pwd/pwd_utils.h
@@ -107,6 +107,14 @@ ErrorOr<void> close();
 // Reads the next entry from the password database.
 ErrorOr<struct passwd *> read_next();
 
+// Searches for a password entry matching the given username using the
+// static process-global buffer.
+ErrorOr<struct passwd *> find_by_name(cpp::string_view name);
+
+// Searches for a password entry matching the given user ID using the
+// static process-global buffer.
+ErrorOr<struct passwd *> find_by_uid(uid_t uid);
+
 // Searches for a password entry matching the given username.
 // The optional path parameter allows unit tests to direct lookups to hermetic
 // test database files without mutating global state.

diff  --git a/libc/test/src/pwd/CMakeLists.txt b/libc/test/src/pwd/CMakeLists.txt
index fe063ebdaf068..043ba44ceb6e9 100644
--- a/libc/test/src/pwd/CMakeLists.txt
+++ b/libc/test/src/pwd/CMakeLists.txt
@@ -65,6 +65,29 @@ add_libc_test(
     libc.src.string.string_utils
 )
 
+add_libc_test(
+  getpwnam_test
+  SUITE
+    libc_pwd_unittests
+  HDRS
+    pwd_test_utils.h
+  SRCS
+    getpwnam_test.cpp
+  DEPENDS
+    libc.hdr.errno_macros
+    libc.hdr.types.gid_t
+    libc.hdr.types.size_t
+    libc.hdr.types.struct_passwd
+    libc.hdr.types.uid_t
+    libc.src.__support.File.file
+    libc.src.__support.File.platform_file
+    libc.src.errno.errno
+    libc.src.pwd.getpwnam
+    libc.src.pwd.pwd_utils
+    libc.src.stdio.remove
+    libc.src.string.string_utils
+)
+
 add_libc_test(
   getpwnam_r_test
   SUITE
@@ -87,6 +110,29 @@ add_libc_test(
     libc.src.string.string_utils
 )
 
+add_libc_test(
+  getpwuid_test
+  SUITE
+    libc_pwd_unittests
+  HDRS
+    pwd_test_utils.h
+  SRCS
+    getpwuid_test.cpp
+  DEPENDS
+    libc.hdr.errno_macros
+    libc.hdr.types.gid_t
+    libc.hdr.types.size_t
+    libc.hdr.types.struct_passwd
+    libc.hdr.types.uid_t
+    libc.src.__support.File.file
+    libc.src.__support.File.platform_file
+    libc.src.errno.errno
+    libc.src.pwd.getpwuid
+    libc.src.pwd.pwd_utils
+    libc.src.stdio.remove
+    libc.src.string.string_utils
+)
+
 add_libc_test(
   getpwuid_r_test
   SUITE

diff  --git a/libc/test/src/pwd/getpwnam_test.cpp b/libc/test/src/pwd/getpwnam_test.cpp
new file mode 100644
index 0000000000000..17b70b9215ebd
--- /dev/null
+++ b/libc/test/src/pwd/getpwnam_test.cpp
@@ -0,0 +1,118 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unit tests for getpwnam.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/errno_macros.h"
+#include "hdr/types/gid_t.h"
+#include "hdr/types/struct_passwd.h"
+#include "hdr/types/uid_t.h"
+#include "pwd_test_utils.h"
+#include "src/__support/libc_errno.h"
+#include "src/pwd/getpwnam.h"
+#include "src/pwd/pwd_utils.h"
+#include "test/UnitTest/Test.h"
+
+using LlvmLibcGetpwnamTest = LlvmLibcPwdTest;
+
+TEST_F(LlvmLibcGetpwnamTest, Success) {
+  const char *content = "root:x:0:0:root:/root:/bin/bash\n"
+                        "bin:x:1:1:bin:/bin:/sbin/nologin\n"
+                        "daemon:x:2:2:daemon:/sbin:/sbin/nologin\n";
+  ScopedPasswdFile test_file(libc_make_test_file_path("getpwnam_success.test"),
+                             content);
+
+  struct passwd *pwd = LIBC_NAMESPACE::getpwnam("bin");
+  ASSERT_NE(pwd, nullptr);
+  ASSERT_STREQ(pwd->pw_name, "bin");
+  ASSERT_STREQ(pwd->pw_passwd, "x");
+  ASSERT_EQ(pwd->pw_uid, static_cast<uid_t>(1));
+  ASSERT_EQ(pwd->pw_gid, static_cast<gid_t>(1));
+  ASSERT_STREQ(pwd->pw_gecos, "bin");
+  ASSERT_STREQ(pwd->pw_dir, "/bin");
+  ASSERT_STREQ(pwd->pw_shell, "/sbin/nologin");
+}
+
+TEST_F(LlvmLibcGetpwnamTest, FirstAndLastEntries) {
+  const char *content = "first:x:100:100:first:/home/first:/bin/sh\n"
+                        "middle:x:101:101:middle:/home/middle:/bin/sh\n"
+                        "last:x:102:102:last:/home/last:/bin/sh\n";
+  ScopedPasswdFile test_file(libc_make_test_file_path("getpwnam_boundary.test"),
+                             content);
+
+  struct passwd *pwd = LIBC_NAMESPACE::getpwnam("first");
+  ASSERT_NE(pwd, nullptr);
+  ASSERT_STREQ(pwd->pw_name, "first");
+  ASSERT_EQ(pwd->pw_uid, static_cast<uid_t>(100));
+
+  pwd = LIBC_NAMESPACE::getpwnam("last");
+  ASSERT_NE(pwd, nullptr);
+  ASSERT_STREQ(pwd->pw_name, "last");
+  ASSERT_EQ(pwd->pw_uid, static_cast<uid_t>(102));
+}
+
+TEST_F(LlvmLibcGetpwnamTest, NotFound) {
+  const char *content = "root:x:0:0:root:/root:/bin/bash\n";
+  ScopedPasswdFile test_file(libc_make_test_file_path("getpwnam_notfound.test"),
+                             content);
+
+  // POSIX specifies that errno must not be changed when an entry is not found.
+  // Pre-set errno to confirm it remains untouched across the call.
+  LIBC_NAMESPACE::libc_errno = ENOENT;
+  struct passwd *pwd = LIBC_NAMESPACE::getpwnam("nonexistent");
+  ASSERT_EQ(pwd, nullptr);
+  ASSERT_ERRNO_EQ(ENOENT);
+
+  // When errno is initially zero, it remains zero.
+  pwd = LIBC_NAMESPACE::getpwnam("nonexistent");
+  ASSERT_EQ(pwd, nullptr);
+  ASSERT_ERRNO_SUCCESS();
+}
+
+TEST_F(LlvmLibcGetpwnamTest, BlankLines) {
+  const char *content = "\nroot:x:0:0:root:/root:/bin/bash\n\n\n"
+                        "bin:x:1:1:bin:/bin:/sbin/nologin\n\n";
+  ScopedPasswdFile test_file(libc_make_test_file_path("getpwnam_blank.test"),
+                             content);
+
+  struct passwd *pwd = LIBC_NAMESPACE::getpwnam("bin");
+  ASSERT_NE(pwd, nullptr);
+  ASSERT_STREQ(pwd->pw_name, "bin");
+  ASSERT_EQ(pwd->pw_uid, static_cast<uid_t>(1));
+}
+
+TEST_F(LlvmLibcGetpwnamTest, FileOpenFailure) {
+  LIBC_NAMESPACE::pwd::TESTONLY_set_passwd_path(
+      "/nonexistent_directory/nonexistent_file");
+
+  struct passwd *pwd = LIBC_NAMESPACE::getpwnam("root");
+  ASSERT_EQ(pwd, nullptr);
+  ASSERT_ERRNO_EQ(ENOENT);
+}
+
+TEST_F(LlvmLibcGetpwnamTest, BufferTooSmall) {
+  // A line exceeding line_buffer (1024 bytes) triggers ERANGE.
+  char content[1100];
+  LIBC_NAMESPACE::internal::strlcpy(content,
+                                    "longuser:x:1000:1000:", sizeof(content));
+  size_t cur = LIBC_NAMESPACE::internal::string_length(content);
+  for (; cur < 1050; ++cur)
+    content[cur] = 'a';
+  LIBC_NAMESPACE::internal::strlcpy(content + cur, ":/home/longuser:/bin/sh\n",
+                                    sizeof(content) - cur);
+
+  ScopedPasswdFile test_file(libc_make_test_file_path("getpwnam_toosmall.test"),
+                             content);
+
+  struct passwd *pwd = LIBC_NAMESPACE::getpwnam("longuser");
+  ASSERT_EQ(pwd, nullptr);
+  ASSERT_ERRNO_EQ(ERANGE);
+}

diff  --git a/libc/test/src/pwd/getpwuid_test.cpp b/libc/test/src/pwd/getpwuid_test.cpp
new file mode 100644
index 0000000000000..ac12e78a762fc
--- /dev/null
+++ b/libc/test/src/pwd/getpwuid_test.cpp
@@ -0,0 +1,117 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unit tests for getpwuid.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/errno_macros.h"
+#include "hdr/types/gid_t.h"
+#include "hdr/types/struct_passwd.h"
+#include "hdr/types/uid_t.h"
+#include "pwd_test_utils.h"
+#include "src/__support/libc_errno.h"
+#include "src/pwd/getpwuid.h"
+#include "src/pwd/pwd_utils.h"
+#include "test/UnitTest/Test.h"
+
+using LlvmLibcGetpwuidTest = LlvmLibcPwdTest;
+
+TEST_F(LlvmLibcGetpwuidTest, Success) {
+  const char *content = "root:x:0:0:root:/root:/bin/bash\n"
+                        "bin:x:1:1:bin:/bin:/sbin/nologin\n"
+                        "daemon:x:2:2:daemon:/sbin:/sbin/nologin\n"
+                        "nobody:x:65534:65534:nobody:/nonexistent:/bin/false\n";
+  ScopedPasswdFile test_file(libc_make_test_file_path("getpwuid_success.test"),
+                             content);
+
+  struct passwd *pwd = LIBC_NAMESPACE::getpwuid(1);
+  ASSERT_NE(pwd, nullptr);
+  ASSERT_STREQ(pwd->pw_name, "bin");
+  ASSERT_EQ(pwd->pw_uid, static_cast<uid_t>(1));
+  ASSERT_EQ(pwd->pw_gid, static_cast<gid_t>(1));
+  ASSERT_STREQ(pwd->pw_dir, "/bin");
+  ASSERT_STREQ(pwd->pw_shell, "/sbin/nologin");
+
+  // Lookup high UID (nobody)
+  pwd = LIBC_NAMESPACE::getpwuid(65534);
+  ASSERT_NE(pwd, nullptr);
+  ASSERT_STREQ(pwd->pw_name, "nobody");
+  ASSERT_EQ(pwd->pw_uid, static_cast<uid_t>(65534));
+}
+
+TEST_F(LlvmLibcGetpwuidTest, RootUidZero) {
+  const char *content = "root:x:0:0:root:/root:/bin/bash\n"
+                        "bin:x:1:1:bin:/bin:/sbin/nologin\n";
+  ScopedPasswdFile test_file(libc_make_test_file_path("getpwuid_zero.test"),
+                             content);
+
+  struct passwd *pwd = LIBC_NAMESPACE::getpwuid(0);
+  ASSERT_NE(pwd, nullptr);
+  ASSERT_STREQ(pwd->pw_name, "root");
+  ASSERT_EQ(pwd->pw_uid, static_cast<uid_t>(0));
+}
+
+TEST_F(LlvmLibcGetpwuidTest, NotFound) {
+  const char *content = "root:x:0:0:root:/root:/bin/bash\n";
+  ScopedPasswdFile test_file(libc_make_test_file_path("getpwuid_notfound.test"),
+                             content);
+
+  // POSIX specifies that errno must not be changed when an entry is not found.
+  // Pre-set errno to confirm it remains untouched across the call.
+  LIBC_NAMESPACE::libc_errno = ENOENT;
+  struct passwd *pwd = LIBC_NAMESPACE::getpwuid(999);
+  ASSERT_EQ(pwd, nullptr);
+  ASSERT_ERRNO_EQ(ENOENT);
+
+  // When errno is initially zero, it remains zero.
+  pwd = LIBC_NAMESPACE::getpwuid(999);
+  ASSERT_EQ(pwd, nullptr);
+  ASSERT_ERRNO_SUCCESS();
+}
+
+TEST_F(LlvmLibcGetpwuidTest, BlankLines) {
+  const char *content = "\nroot:x:0:0:root:/root:/bin/bash\n\n\n"
+                        "bin:x:1:1:bin:/bin:/sbin/nologin\n\n";
+  ScopedPasswdFile test_file(libc_make_test_file_path("getpwuid_blank.test"),
+                             content);
+
+  struct passwd *pwd = LIBC_NAMESPACE::getpwuid(1);
+  ASSERT_NE(pwd, nullptr);
+  ASSERT_STREQ(pwd->pw_name, "bin");
+  ASSERT_EQ(pwd->pw_uid, static_cast<uid_t>(1));
+}
+
+TEST_F(LlvmLibcGetpwuidTest, FileOpenFailure) {
+  LIBC_NAMESPACE::pwd::TESTONLY_set_passwd_path(
+      "/nonexistent_directory/nonexistent_file");
+
+  struct passwd *pwd = LIBC_NAMESPACE::getpwuid(0);
+  ASSERT_EQ(pwd, nullptr);
+  ASSERT_ERRNO_EQ(ENOENT);
+}
+
+TEST_F(LlvmLibcGetpwuidTest, BufferTooSmall) {
+  // A line exceeding line_buffer (1024 bytes) triggers ERANGE.
+  char content[1100];
+  LIBC_NAMESPACE::internal::strlcpy(content,
+                                    "longuser:x:1000:1000:", sizeof(content));
+  size_t cur = LIBC_NAMESPACE::internal::string_length(content);
+  for (; cur < 1050; ++cur)
+    content[cur] = 'a';
+  LIBC_NAMESPACE::internal::strlcpy(content + cur, ":/home/longuser:/bin/sh\n",
+                                    sizeof(content) - cur);
+
+  ScopedPasswdFile test_file(libc_make_test_file_path("getpwuid_toosmall.test"),
+                             content);
+
+  struct passwd *pwd = LIBC_NAMESPACE::getpwuid(1000);
+  ASSERT_EQ(pwd, nullptr);
+  ASSERT_ERRNO_EQ(ERANGE);
+}


        


More information about the libc-commits mailing list