[libc-commits] [libc] [libc] Implement execlp in unistd (PR #232901)
Aman Maurya via libc-commits
libc-commits at lists.llvm.org
Tue Oct 20 08:02:40 PDT 2026
https://github.com/amanmaurya92 updated https://github.com/llvm/llvm-project/pull/232901
>From 1e290ab644fbed089878faa5aa28b7d830b33955 Mon Sep 17 00:00:00 2001
From: amanmaurya92 <amanmaurya9209 at gmail.com>
Date: Sat, 17 Oct 2026 00:44:39 +0530
Subject: [PATCH 1/2] [libc] Implement execlp in unistd
Implement the standard POSIX function `execlp` in `<unistd.h>`.
Part of #232374.
Assisted by Antigravity and reviewed by Aman Maurya.
---
libc/config/linux/aarch64/entrypoints.txt | 1 +
libc/config/linux/riscv/entrypoints.txt | 1 +
libc/config/linux/x86_64/entrypoints.txt | 1 +
libc/include/unistd.yaml | 8 ++
libc/src/unistd/CMakeLists.txt | 7 ++
libc/src/unistd/execlp.h | 25 +++++++
libc/src/unistd/linux/CMakeLists.txt | 14 ++++
libc/src/unistd/linux/execlp.cpp | 55 ++++++++++++++
.../integration/src/unistd/CMakeLists.txt | 20 +++++
.../integration/src/unistd/execlp_test.cpp | 74 +++++++++++++++++++
libc/test/src/unistd/CMakeLists.txt | 13 ++++
libc/test/src/unistd/execlp_test.cpp | 38 ++++++++++
12 files changed, 257 insertions(+)
create mode 100644 libc/src/unistd/execlp.h
create mode 100644 libc/src/unistd/linux/execlp.cpp
create mode 100644 libc/test/integration/src/unistd/execlp_test.cpp
create mode 100644 libc/test/src/unistd/execlp_test.cpp
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 42ce377d7dca9a..04f4e0ebaf9b1a 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1454,6 +1454,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.unistd.confstr
libc.src.unistd.environ
libc.src.unistd.execl
+ libc.src.unistd.execlp
libc.src.unistd.execv
libc.src.unistd.fork
libc.src.unistd.getopt
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 7e0511487c2cf5..9e97bb4948df27 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1653,6 +1653,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.unistd.confstr
libc.src.unistd.environ
libc.src.unistd.execl
+ libc.src.unistd.execlp
libc.src.unistd.execv
libc.src.unistd.fork
libc.src.unistd.getopt
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 155ae28d753bec..b9443254a9e4e1 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1679,6 +1679,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.unistd.confstr
libc.src.unistd.environ
libc.src.unistd.execl
+ libc.src.unistd.execlp
libc.src.unistd.execv
libc.src.unistd.fork
libc.src.unistd.getopt
diff --git a/libc/include/unistd.yaml b/libc/include/unistd.yaml
index 5964e35b6ce5d2..462407707e255e 100644
--- a/libc/include/unistd.yaml
+++ b/libc/include/unistd.yaml
@@ -222,6 +222,14 @@ functions:
- type: const char *
- type: const char *
- type: '...'
+ - name: execlp
+ standards:
+ - posix
+ return_type: int
+ arguments:
+ - type: const char *
+ - type: const char *
+ - type: '...'
- name: execv
standards:
- posix
diff --git a/libc/src/unistd/CMakeLists.txt b/libc/src/unistd/CMakeLists.txt
index 27b74b8ca2de3c..62c637bd5b69f1 100644
--- a/libc/src/unistd/CMakeLists.txt
+++ b/libc/src/unistd/CMakeLists.txt
@@ -161,6 +161,13 @@ add_entrypoint_object(
.${LIBC_TARGET_OS}.execle
)
+add_entrypoint_object(
+ execlp
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.execlp
+)
+
add_entrypoint_object(
execv
ALIAS
diff --git a/libc/src/unistd/execlp.h b/libc/src/unistd/execlp.h
new file mode 100644
index 00000000000000..3b1c8800484818
--- /dev/null
+++ b/libc/src/unistd/execlp.h
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 header for execlp.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_UNISTD_EXECLP_H
+#define LLVM_LIBC_SRC_UNISTD_EXECLP_H
+
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int execlp(const char *file, const char *arg0, ...);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_UNISTD_EXECLP_H
diff --git a/libc/src/unistd/linux/CMakeLists.txt b/libc/src/unistd/linux/CMakeLists.txt
index 61030ec7e12283..2d4f906a299713 100644
--- a/libc/src/unistd/linux/CMakeLists.txt
+++ b/libc/src/unistd/linux/CMakeLists.txt
@@ -235,6 +235,20 @@ add_entrypoint_object(
libc.src.errno.errno
)
+add_entrypoint_object(
+ execlp
+ SRCS
+ execlp.cpp
+ HDRS
+ ../execlp.h
+ DEPENDS
+ libc.hdr.types.size_t
+ libc.src.__support.common
+ libc.src.__support.macros.config
+ libc.src.__support.macros.null_check
+ libc.src.unistd.execvp
+)
+
add_entrypoint_object(
execv
SRCS
diff --git a/libc/src/unistd/linux/execlp.cpp b/libc/src/unistd/linux/execlp.cpp
new file mode 100644
index 00000000000000..8114cda0857858
--- /dev/null
+++ b/libc/src/unistd/linux/execlp.cpp
@@ -0,0 +1,55 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+/// Linux implementation of execlp.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/unistd/execlp.h"
+
+#include "hdr/types/size_t.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/null_check.h"
+#include "src/unistd/execvp.h"
+
+#include <stdarg.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, execlp, (const char *file, const char *arg0, ...)) {
+ LIBC_CRASH_ON_NULLPTR(arg0);
+
+ va_list varargs, varargs_copy;
+ va_start(varargs, arg0);
+ va_copy(varargs_copy, varargs);
+
+ size_t argc = 1;
+ while (va_arg(varargs, const char *) != nullptr)
+ ++argc;
+ va_end(varargs);
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wvla"
+#if __has_warning("-Wvla-cxx-extension")
+#pragma GCC diagnostic ignored "-Wvla-cxx-extension"
+#endif
+ char *argv[argc + 1];
+#pragma GCC diagnostic pop
+ argv[0] = const_cast<char *>(arg0);
+
+ for (size_t i = 1; i < argc; ++i)
+ argv[i] = va_arg(varargs_copy, char *);
+ va_end(varargs_copy);
+ argv[argc] = nullptr;
+
+ return LIBC_NAMESPACE::execvp(file, argv);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/integration/src/unistd/CMakeLists.txt b/libc/test/integration/src/unistd/CMakeLists.txt
index cc04b374a83789..31495c9d2b27e2 100644
--- a/libc/test/integration/src/unistd/CMakeLists.txt
+++ b/libc/test/integration/src/unistd/CMakeLists.txt
@@ -224,4 +224,24 @@ add_integration_test(
libc.src.unistd.fork
ENV
EXECV_TEST=PASS
+
+add_integration_test(
+ execlp_test
+ SUITE
+ unistd-integration-tests
+ SRCS
+ execlp_test.cpp
+ DEPENDS
+ libc_execv_test_normal_exit
+ libc_exec_test_signal_exit
+ libc.hdr.signal_macros
+ libc.hdr.sys_wait_macros
+ libc.src.errno.errno
+ libc.src.sys.wait.waitpid
+ libc.src.unistd.environ
+ libc.src.unistd.execlp
+ libc.src.unistd.fork
+ ENV
+ EXECV_TEST=PASS
+ PATH=.
)
diff --git a/libc/test/integration/src/unistd/execlp_test.cpp b/libc/test/integration/src/unistd/execlp_test.cpp
new file mode 100644
index 00000000000000..a8888f540298cb
--- /dev/null
+++ b/libc/test/integration/src/unistd/execlp_test.cpp
@@ -0,0 +1,74 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+/// Integration test for execlp.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/sys/wait/waitpid.h"
+#include "src/unistd/execlp.h"
+#include "src/unistd/fork.h"
+
+#include "hdr/signal_macros.h"
+#include "hdr/sys_wait_macros.h"
+#include "test/IntegrationTest/test.h"
+
+void fork_and_execlp_path_search() {
+ pid_t pid = LIBC_NAMESPACE::fork();
+ if (pid == 0) {
+ LIBC_NAMESPACE::execlp("libc_execv_test_normal_exit",
+ "libc_execv_test_normal_exit",
+ static_cast<char *>(nullptr));
+ }
+ ASSERT_TRUE(pid > 0);
+ int status;
+ pid_t cpid = LIBC_NAMESPACE::waitpid(pid, &status, 0);
+ ASSERT_TRUE(cpid > 0);
+ ASSERT_EQ(cpid, pid);
+ ASSERT_TRUE(WIFEXITED(status));
+}
+
+void fork_and_execlp_slash_path() {
+ pid_t pid = LIBC_NAMESPACE::fork();
+ if (pid == 0) {
+ LIBC_NAMESPACE::execlp("./libc_execv_test_normal_exit",
+ "libc_execv_test_normal_exit",
+ static_cast<char *>(nullptr));
+ }
+ ASSERT_TRUE(pid > 0);
+ int status;
+ pid_t cpid = LIBC_NAMESPACE::waitpid(pid, &status, 0);
+ ASSERT_TRUE(cpid > 0);
+ ASSERT_EQ(cpid, pid);
+ ASSERT_TRUE(WIFEXITED(status));
+}
+
+void fork_and_execlp_signal_exit() {
+ pid_t pid = LIBC_NAMESPACE::fork();
+ if (pid == 0) {
+ LIBC_NAMESPACE::execlp("libc_exec_test_signal_exit",
+ "libc_exec_test_signal_exit",
+ static_cast<char *>(nullptr));
+ }
+ ASSERT_TRUE(pid > 0);
+ int status;
+ pid_t cpid = LIBC_NAMESPACE::waitpid(pid, &status, 0);
+ ASSERT_TRUE(cpid > 0);
+ ASSERT_EQ(cpid, pid);
+ ASSERT_FALSE(WIFEXITED(status));
+ ASSERT_TRUE(WTERMSIG(status) == SIGUSR1);
+}
+
+TEST_MAIN([[maybe_unused]] int argc, [[maybe_unused]] char **argv,
+ [[maybe_unused]] char **envp) {
+ fork_and_execlp_path_search();
+ fork_and_execlp_slash_path();
+ fork_and_execlp_signal_exit();
+ return 0;
+}
diff --git a/libc/test/src/unistd/CMakeLists.txt b/libc/test/src/unistd/CMakeLists.txt
index 2e8d9bb8e2509f..0aa7f99a00a85c 100644
--- a/libc/test/src/unistd/CMakeLists.txt
+++ b/libc/test/src/unistd/CMakeLists.txt
@@ -245,6 +245,19 @@ add_libc_test(
libc.test.UnitTest.ErrnoSetterMatcher
)
+add_libc_test(
+ execlp_test
+ SUITE
+ libc_unistd_unittests
+ SRCS
+ execlp_test.cpp
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.src.unistd.execlp
+ libc.test.UnitTest.ErrnoCheckingTest
+ libc.test.UnitTest.ErrnoSetterMatcher
+)
+
add_libc_test(
fexecve_test
SUITE
diff --git a/libc/test/src/unistd/execlp_test.cpp b/libc/test/src/unistd/execlp_test.cpp
new file mode 100644
index 00000000000000..66c50f69e6fbb1
--- /dev/null
+++ b/libc/test/src/unistd/execlp_test.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+/// Unittests for execlp.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/errno_macros.h"
+#include "src/unistd/execlp.h"
+#include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/Test.h"
+
+using LlvmLibcExeclpTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+
+TEST_F(LlvmLibcExeclpTest, NonExistentFile) {
+ using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
+ ASSERT_THAT(LIBC_NAMESPACE::execlp("nonexistent_binary_xyz_123",
+ "nonexistent_binary_xyz_123", nullptr),
+ Fails(ENOENT));
+}
+
+TEST_F(LlvmLibcExeclpTest, NonExistentPathWithSlash) {
+ using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
+ ASSERT_THAT(LIBC_NAMESPACE::execlp("/nonexistent/path/xyz", "xyz", nullptr),
+ Fails(ENOENT));
+}
+
+TEST_F(LlvmLibcExeclpTest, EmptyFileName) {
+ using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
+ ASSERT_THAT(LIBC_NAMESPACE::execlp("", "", nullptr), Fails(ENOENT));
+}
>From 33e6fb135b710d439b6ea5ab72f4fb5b3540c2eb Mon Sep 17 00:00:00 2001
From: amanmaurya92 <amanmaurya9209 at gmail.com>
Date: Sat, 17 Oct 2026 02:23:04 +0530
Subject: [PATCH 2/2] Fix cmake-format in execlp integration test
Assisted by Antigravity and reviewed by Aman Maurya.
---
libc/test/integration/src/unistd/CMakeLists.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/libc/test/integration/src/unistd/CMakeLists.txt b/libc/test/integration/src/unistd/CMakeLists.txt
index 31495c9d2b27e2..d59fa99471650a 100644
--- a/libc/test/integration/src/unistd/CMakeLists.txt
+++ b/libc/test/integration/src/unistd/CMakeLists.txt
@@ -224,6 +224,7 @@ add_integration_test(
libc.src.unistd.fork
ENV
EXECV_TEST=PASS
+)
add_integration_test(
execlp_test
More information about the libc-commits
mailing list