[libc-commits] [libc] [libc] Implement execvp in unistd (PR #232427)
Pavel Labath via libc-commits
libc-commits at lists.llvm.org
Fri Oct 16 00:47:15 PDT 2026
================
@@ -0,0 +1,162 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 execvp.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/unistd/execvp.h"
+
+#include "hdr/errno_macros.h"
+#include "hdr/types/size_t.h"
+#include "src/__support/CPP/string_view.h"
+#include "src/__support/CPP/stringstream.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/execve.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/null_check.h"
+#include "src/unistd/environ.h"
+
+#include <linux/limits.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+namespace {
+
+LIBC_INLINE const char *get_path() {
+ if (LIBC_NAMESPACE::environ == nullptr)
+ return nullptr;
+
+ for (char **env = LIBC_NAMESPACE::environ; *env != nullptr; ++env) {
+ cpp::string_view entry(*env);
+ if (entry.starts_with("PATH="))
+ return *env + 5;
+ }
+ return nullptr;
+}
+
+LIBC_INLINE int execve_with_fallback(const char *path, char *const argv[],
+ char *const envp[]) {
+ auto ret = linux_syscalls::execve(path, argv, envp);
+ if (!ret && ret.error() == ENOEXEC) {
+ size_t argc = 0;
+ while (argv[argc] != nullptr)
+ ++argc;
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wvla"
+#if __has_warning("-Wvla-cxx-extension")
+#pragma GCC diagnostic ignored "-Wvla-cxx-extension"
+#endif
+ char *new_argv[argc + 2];
+#pragma GCC diagnostic pop
+ new_argv[0] = const_cast<char *>("sh");
+ new_argv[1] = const_cast<char *>(path);
+ for (size_t i = 1; i <= argc; ++i)
+ new_argv[i + 1] = argv[i];
+
+ ret = linux_syscalls::execve("/bin/sh", new_argv, envp);
+ }
+ if (!ret) {
+ libc_errno = ret.error();
+ return -1;
+ }
+ return *ret;
+}
+
+} // namespace
+
+LLVM_LIBC_FUNCTION(int, execvp, (const char *file, char *const argv[])) {
+ LIBC_CRASH_ON_NULLPTR(file);
+
+ if (file[0] == '\0') {
+ libc_errno = ENOENT;
+ return -1;
+ }
+
+ char *const *envp = const_cast<char *const *>(LIBC_NAMESPACE::environ);
+
+ cpp::string_view file_view(file);
+ if (file_view.contains('/'))
+ return execve_with_fallback(file, argv, envp);
+
+ const char *path = get_path();
+ // POSIX standard default path if PATH is not set.
+ if (path == nullptr)
+ path = ":/bin:/usr/bin";
----------------
labath wrote:
Are you sure about that? I'd be surprised if "." was on the default path -- and in the first place, no less
```suggestion
path = "/bin:/usr/bin";
```
https://github.com/llvm/llvm-project/pull/232427
More information about the libc-commits
mailing list