[libc-commits] [libc] 3f96581 - [libc] Add POSIX execv and execve functions.
Siva Chandra Reddy via libc-commits
libc-commits at lists.llvm.org
Thu Oct 6 12:50:34 PDT 2022
Author: Siva Chandra Reddy
Date: 2022-10-06T19:50:23Z
New Revision: 3f965818b6a98f4dedba1a5c3517f661c018e62e
URL: https://github.com/llvm/llvm-project/commit/3f965818b6a98f4dedba1a5c3517f661c018e62e
DIFF: https://github.com/llvm/llvm-project/commit/3f965818b6a98f4dedba1a5c3517f661c018e62e.diff
LOG: [libc] Add POSIX execv and execve functions.
The POSIX global variable environ has also been added.
Reviewed By: michaelrj
Differential Revision: https://reviews.llvm.org/D135351
Added:
libc/include/llvm-libc-types/__exec_argv_t.h
libc/include/llvm-libc-types/__exec_envp_t.h
libc/src/unistd/environ.cpp
libc/src/unistd/environ.h
libc/src/unistd/execv.h
libc/src/unistd/execve.h
libc/src/unistd/linux/execv.cpp
libc/src/unistd/linux/execve.cpp
libc/test/integration/src/unistd/execv_test.cpp
libc/test/integration/src/unistd/execv_test_normal_exit.cpp
libc/test/integration/src/unistd/execv_test_signal_exit.cpp
libc/test/integration/src/unistd/execve_test.cpp
Modified:
libc/cmake/modules/LLVMLibCTestRules.cmake
libc/config/linux/aarch64/entrypoints.txt
libc/config/linux/api.td
libc/config/linux/x86_64/entrypoints.txt
libc/include/CMakeLists.txt
libc/include/llvm-libc-types/CMakeLists.txt
libc/loader/linux/aarch64/start.cpp
libc/loader/linux/x86_64/CMakeLists.txt
libc/loader/linux/x86_64/start.cpp
libc/spec/posix.td
libc/src/unistd/CMakeLists.txt
libc/src/unistd/linux/CMakeLists.txt
libc/test/integration/src/unistd/CMakeLists.txt
Removed:
################################################################################
diff --git a/libc/cmake/modules/LLVMLibCTestRules.cmake b/libc/cmake/modules/LLVMLibCTestRules.cmake
index f1e8c2c32af20..f4f0a70a51b65 100644
--- a/libc/cmake/modules/LLVMLibCTestRules.cmake
+++ b/libc/cmake/modules/LLVMLibCTestRules.cmake
@@ -431,7 +431,8 @@ function(add_integration_test test_name)
APPEND fq_deps_list
libc.src.__support.threads.thread
libc.src.stdlib.atexit
- libc.src.stdlib.exit)
+ libc.src.stdlib.exit
+ libc.src.unistd.environ)
list(REMOVE_DUPLICATES fq_deps_list)
# We don't want memory functions to be dependencies on integration tests.
@@ -533,7 +534,8 @@ function(add_integration_test test_name)
add_dependencies(${fq_target_name}
${fq_target_name}.__copy_loader__
${fq_libc_target_name}
- libc.utils.IntegrationTest.test)
+ libc.utils.IntegrationTest.test
+ ${INTEGRATION_TEST_DEPENDS})
add_custom_command(
TARGET ${fq_target_name}
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index e88068bbaaa58..92e3cdce6a19f 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -377,6 +377,9 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.time.mktime
libc.src.time.nanosleep
libc.src.time.clock_gettime
+
+ # unistd.h entrypoints
+ libc.src.unistd.environ
)
endif()
diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td
index 01a7814e2d281..bf8dd847f1ab1 100644
--- a/libc/config/linux/api.td
+++ b/libc/config/linux/api.td
@@ -259,7 +259,7 @@ def DirentAPI : PublicAPI<"dirent.h"> {
}
def UniStdAPI : PublicAPI<"unistd.h"> {
- let Types = ["off_t", "pid_t", "size_t", "ssize_t", "uid_t"];
+ let Types = ["__exec_argv_t", "__exec_envp_t", "off_t", "pid_t", "size_t", "ssize_t", "uid_t"];
}
def SysResourceAPI : PublicAPI<"sys/resource.h"> {
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 98106c71d512a..b8e88e0dae5df 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -143,6 +143,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.unistd.dup
libc.src.unistd.dup2
libc.src.unistd.dup3
+ libc.src.unistd.execve
libc.src.unistd.fchdir
libc.src.unistd.fsync
libc.src.unistd.ftruncate
@@ -412,6 +413,8 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.time.clock_gettime
# unistd.h entrypoints
+ libc.src.unistd.environ
+ libc.src.unistd.execv
libc.src.unistd.fork
libc.src.unistd.__llvm_libc_syscall
)
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index 63f9dfe0b547e..35336d38de8dd 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -175,6 +175,8 @@ add_gen_header(
.llvm_libc_common_h
.llvm-libc-macros.file_seek_macros
.llvm-libc-macros.unistd_macros
+ .llvm-libc-types.__exec_argv_t
+ .llvm-libc-types.__exec_envp_t
.llvm-libc-types.off_t
.llvm-libc-types.pid_t
.llvm-libc-types.size_t
diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt
index b9e87eb888996..ffce26d798b5f 100644
--- a/libc/include/llvm-libc-types/CMakeLists.txt
+++ b/libc/include/llvm-libc-types/CMakeLists.txt
@@ -2,6 +2,8 @@ add_header(off64_t HDR off64_t.h)
add_header(size_t HDR size_t.h)
add_header(__bsearchcompare_t HDR __bsearchcompare_t.h)
add_header(__call_once_func_t HDR __call_once_func_t.h)
+add_header(__exec_argv_t HDR __exec_argv_t.h)
+add_header(__exec_envp_t HDR __exec_envp_t.h)
add_header(__futex_word HDR __futex_word.h)
add_header(__mutex_type HDR __mutex_type.h DEPENDS .__futex_word)
add_header(__pthread_once_func_t HDR __pthread_once_func_t.h)
diff --git a/libc/include/llvm-libc-types/__exec_argv_t.h b/libc/include/llvm-libc-types/__exec_argv_t.h
new file mode 100644
index 0000000000000..35b687d9685d4
--- /dev/null
+++ b/libc/include/llvm-libc-types/__exec_argv_t.h
@@ -0,0 +1,14 @@
+//===-- Definition of type __exec_argv_t ----------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __LLVM_LIBC_TYPES_EXEC_ARGV_T_H__
+#define __LLVM_LIBC_TYPES_EXEC_ARGV_T_H__
+
+typedef char *const __exec_argv_t[];
+
+#endif // __LLVM_LIBC_TYPES_EXEC_ARGV_T_H__
diff --git a/libc/include/llvm-libc-types/__exec_envp_t.h b/libc/include/llvm-libc-types/__exec_envp_t.h
new file mode 100644
index 0000000000000..06eb2ddcb1fbd
--- /dev/null
+++ b/libc/include/llvm-libc-types/__exec_envp_t.h
@@ -0,0 +1,14 @@
+//===-- Definition of type __exec_envp_t ----------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __LLVM_LIBC_TYPES_EXEC_ENVP_T_H__
+#define __LLVM_LIBC_TYPES_EXEC_ENVP_T_H__
+
+typedef char *const __exec_envp_t[];
+
+#endif // __LLVM_LIBC_TYPES_EXEC_ENVP_T_H__
diff --git a/libc/loader/linux/aarch64/start.cpp b/libc/loader/linux/aarch64/start.cpp
index 7234c2a105049..b02ea7d3a6131 100644
--- a/libc/loader/linux/aarch64/start.cpp
+++ b/libc/loader/linux/aarch64/start.cpp
@@ -20,6 +20,7 @@
#include <stdint.h>
#include <sys/mman.h>
#include <sys/syscall.h>
+#include <unistd.h>
extern "C" int main(int, char **, char **);
@@ -147,6 +148,9 @@ __attribute__((noinline)) static void do_start() {
while (*env_end_marker)
++env_end_marker;
+ // Initialize the POSIX global declared in unistd.h
+ environ = reinterpret_cast<char **>(env_ptr);
+
// After the env array, is the aux-vector. The end of the aux-vector is
// denoted by an AT_NULL entry.
Elf64_Phdr *programHdrTable = nullptr;
diff --git a/libc/loader/linux/x86_64/CMakeLists.txt b/libc/loader/linux/x86_64/CMakeLists.txt
index fa27ef1eca657..f62ad0ad83262 100644
--- a/libc/loader/linux/x86_64/CMakeLists.txt
+++ b/libc/loader/linux/x86_64/CMakeLists.txt
@@ -6,11 +6,13 @@ add_loader_object(
libc.config.linux.app_h
libc.include.sys_mman
libc.include.sys_syscall
+ libc.include.unistd
libc.src.__support.threads.thread
libc.src.__support.OSUtil.osutil
libc.src.stdlib.exit
libc.src.stdlib.atexit
libc.src.string.memory_utils.memcpy_implementation
+ libc.src.unistd.environ
COMPILE_OPTIONS
-fno-omit-frame-pointer
-ffreestanding # To avoid compiler warnings about calling the main function.
diff --git a/libc/loader/linux/x86_64/start.cpp b/libc/loader/linux/x86_64/start.cpp
index 19670fa1a41db..6ddb344b339af 100644
--- a/libc/loader/linux/x86_64/start.cpp
+++ b/libc/loader/linux/x86_64/start.cpp
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <sys/mman.h>
#include <sys/syscall.h>
+#include <unistd.h>
extern "C" int main(int, char **, char **);
@@ -167,6 +168,9 @@ extern "C" void _start() {
while (*env_end_marker)
++env_end_marker;
+ // Initialize the POSIX global declared in unistd.h
+ environ = reinterpret_cast<char **>(env_ptr);
+
// After the env array, is the aux-vector. The end of the aux-vector is
// denoted by an AT_NULL entry.
Elf64_Phdr *programHdrTable = nullptr;
diff --git a/libc/spec/posix.td b/libc/spec/posix.td
index 369455bb37c21..69b973203816b 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -45,6 +45,9 @@ def ConstStructDirentPtrPtr : ConstType<StructDirentPtrPtr>;
def StructTimeSpec : NamedType<"struct timespec">;
def StructTimeSpecPtr : PtrType<StructTimeSpec>;
+def ExecArgvT : NamedType<"__exec_argv_t">;
+def ExecEnvpT : NamedType<"__exec_envp_t">;
+
def POSIX : StandardSpec<"POSIX"> {
PtrType CharPtr = PtrType<CharType>;
RestrictedPtrType RestrictedCharPtr = RestrictedPtrType<CharType>;
@@ -299,6 +302,8 @@ def POSIX : StandardSpec<"POSIX"> {
"unistd.h",
[], // Macros
[
+ ExecArgvT,
+ ExecEnvpT,
OffTType,
SSizeTType,
SizeTType,
@@ -342,6 +347,16 @@ def POSIX : StandardSpec<"POSIX"> {
RetValSpec<IntType>,
[ArgSpec<IntType>]
>,
+ FunctionSpec<
+ "execv",
+ RetValSpec<IntType>,
+ [ArgSpec<ConstCharPtr>, ArgSpec<ExecArgvT>]
+ >,
+ FunctionSpec<
+ "execve",
+ RetValSpec<IntType>,
+ [ArgSpec<ConstCharPtr>, ArgSpec<ExecArgvT>, ArgSpec<ExecEnvpT>]
+ >,
FunctionSpec<
"fork",
RetValSpec<PidT>,
@@ -512,6 +527,9 @@ def POSIX : StandardSpec<"POSIX"> {
RetValSpec<SSizeTType>,
[ArgSpec<IntType>, ArgSpec<ConstVoidPtr>, ArgSpec<SizeTType>]
>,
+ ],
+ [
+ ObjectSpec<"environ", "char **">,
]
>;
diff --git a/libc/src/unistd/CMakeLists.txt b/libc/src/unistd/CMakeLists.txt
index a460b5d18055f..a9d88ee9441c8 100644
--- a/libc/src/unistd/CMakeLists.txt
+++ b/libc/src/unistd/CMakeLists.txt
@@ -58,6 +58,20 @@ add_entrypoint_object(
.${LIBC_TARGET_OS}.fork
)
+add_entrypoint_object(
+ execv
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.execv
+)
+
+add_entrypoint_object(
+ execve
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.execve
+)
+
add_entrypoint_object(
fsync
ALIAS
@@ -211,3 +225,11 @@ add_entrypoint_object(
DEPENDS
.${LIBC_TARGET_OS}.write
)
+
+add_entrypoint_object(
+ environ
+ SRCS
+ environ.cpp
+ HDRS
+ environ.h
+)
diff --git a/libc/src/unistd/environ.cpp b/libc/src/unistd/environ.cpp
new file mode 100644
index 0000000000000..d3f6f4cca4712
--- /dev/null
+++ b/libc/src/unistd/environ.cpp
@@ -0,0 +1,14 @@
+//===-- Declaration of POSIX environ --------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+namespace __llvm_libc {
+
+// This is initialized to the correct value by the statup code.
+extern "C" char **environ = nullptr;
+
+} // namespace __llvm_libc
diff --git a/libc/src/unistd/environ.h b/libc/src/unistd/environ.h
new file mode 100644
index 0000000000000..eb808411ac187
--- /dev/null
+++ b/libc/src/unistd/environ.h
@@ -0,0 +1,18 @@
+//===-- Declaration of POSIX environ ----------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_UNISTD_ENVIRON_H
+#define LLVM_LIBC_SRC_UNISTD_ENVIRON_H
+
+namespace __llvm_libc {
+
+extern "C" char **environ;
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_UNISTD_ENVIRON_H
diff --git a/libc/src/unistd/execv.h b/libc/src/unistd/execv.h
new file mode 100644
index 0000000000000..f26a5831781c4
--- /dev/null
+++ b/libc/src/unistd/execv.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for execv -------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_UNISTD_EXECV_H
+#define LLVM_LIBC_SRC_UNISTD_EXECV_H
+
+namespace __llvm_libc {
+
+int execv(const char *path, char *const argv[]);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_UNISTD_EXECV_H
diff --git a/libc/src/unistd/execve.h b/libc/src/unistd/execve.h
new file mode 100644
index 0000000000000..48ac78d9b575d
--- /dev/null
+++ b/libc/src/unistd/execve.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for execve ------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_UNISTD_EXECVE_H
+#define LLVM_LIBC_SRC_UNISTD_EXECVE_H
+
+namespace __llvm_libc {
+
+int execve(const char *path, char *const argv[], char *const envp[]);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_UNISTD_EXECVE_H
diff --git a/libc/src/unistd/linux/CMakeLists.txt b/libc/src/unistd/linux/CMakeLists.txt
index a3f7ef4187f01..3529222ace45f 100644
--- a/libc/src/unistd/linux/CMakeLists.txt
+++ b/libc/src/unistd/linux/CMakeLists.txt
@@ -105,6 +105,33 @@ add_entrypoint_object(
libc.src.errno.errno
)
+add_entrypoint_object(
+ execv
+ SRCS
+ execv.cpp
+ HDRS
+ ../execv.h
+ DEPENDS
+ libc.include.errno
+ libc.include.sys_syscall
+ libc.src.__support.OSUtil.osutil
+ libc.src.errno.errno
+ libc.src.unistd.environ
+)
+
+add_entrypoint_object(
+ execve
+ SRCS
+ execve.cpp
+ HDRS
+ ../execve.h
+ DEPENDS
+ libc.include.errno
+ libc.include.sys_syscall
+ libc.src.__support.OSUtil.osutil
+ libc.src.errno.errno
+)
+
add_entrypoint_object(
fsync
SRCS
diff --git a/libc/src/unistd/linux/execv.cpp b/libc/src/unistd/linux/execv.cpp
new file mode 100644
index 0000000000000..8eef5745ad4aa
--- /dev/null
+++ b/libc/src/unistd/linux/execv.cpp
@@ -0,0 +1,33 @@
+//===-- Linux implementation of execv -------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/unistd/execv.h"
+#include "src/unistd/environ.h"
+
+#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/common.h"
+
+#include <errno.h>
+#include <sys/syscall.h> // For syscall numbers.
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, execv, (const char *path, char *const argv[])) {
+ long ret =
+ __llvm_libc::syscall_impl(SYS_execve, path, argv, __llvm_libc::environ);
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+
+ // Control will not reach here on success but have a return statement will
+ // keep the compilers happy.
+ return ret;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/unistd/linux/execve.cpp b/libc/src/unistd/linux/execve.cpp
new file mode 100644
index 0000000000000..d490f662c1a68
--- /dev/null
+++ b/libc/src/unistd/linux/execve.cpp
@@ -0,0 +1,33 @@
+//===-- Linux implementation of execve ------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/unistd/execve.h"
+#include "src/unistd/environ.h"
+
+#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/common.h"
+
+#include <errno.h>
+#include <sys/syscall.h> // For syscall numbers.
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(int, execve,
+ (const char *path, char *const argv[], char *const envp[])) {
+ long ret = __llvm_libc::syscall_impl(SYS_execve, path, argv, envp);
+ if (ret < 0) {
+ errno = -ret;
+ return -1;
+ }
+
+ // Control will not reach here on success but have a return statement will
+ // keep the compilers happy.
+ return ret;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/test/integration/src/unistd/CMakeLists.txt b/libc/test/integration/src/unistd/CMakeLists.txt
index 338e1ee04a2fa..23adb29c7326c 100644
--- a/libc/test/integration/src/unistd/CMakeLists.txt
+++ b/libc/test/integration/src/unistd/CMakeLists.txt
@@ -20,3 +20,65 @@ add_integration_test(
libc.src.sys.wait.waitpid
libc.src.unistd.fork
)
+
+add_executable(
+ libc_execv_test_normal_exit
+ EXCLUDE_FROM_ALL
+ execv_test_normal_exit.cpp
+)
+set_target_properties(
+ libc_execv_test_normal_exit
+ PROPERTIES
+ OUTPUT_NAME libc_execv_test_normal_exit
+ RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+add_executable(
+ libc_execv_test_signal_exit
+ EXCLUDE_FROM_ALL
+ execv_test_signal_exit.cpp
+)
+set_target_properties(
+ libc_execv_test_signal_exit
+ PROPERTIES
+ OUTPUT_NAME libc_execv_test_signal_exit
+ RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+add_integration_test(
+ execv_test
+ SUITE
+ unistd-integration-tests
+ SRCS
+ execv_test.cpp
+ LOADER
+ libc.loader.linux.crt1
+ DEPENDS
+ libc_execv_test_normal_exit
+ libc_execv_test_signal_exit
+ libc.include.errno
+ libc.src.sys.wait.waitpid
+ libc.src.unistd.execv
+ libc.src.unistd.fork
+ ENV
+ EXECV_TEST=PASS
+)
+
+add_integration_test(
+ execve_test
+ SUITE
+ unistd-integration-tests
+ SRCS
+ execve_test.cpp
+ LOADER
+ libc.loader.linux.crt1
+ DEPENDS
+ libc_execv_test_normal_exit
+ libc_execv_test_signal_exit
+ libc.include.errno
+ libc.src.sys.wait.waitpid
+ libc.src.unistd.execve
+ libc.src.unistd.fork
+ ENV
+ EXECV_TEST=PASS
+)
diff --git a/libc/test/integration/src/unistd/execv_test.cpp b/libc/test/integration/src/unistd/execv_test.cpp
new file mode 100644
index 0000000000000..8df5752bc14d0
--- /dev/null
+++ b/libc/test/integration/src/unistd/execv_test.cpp
@@ -0,0 +1,59 @@
+//===-- Unittests for execv -----------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/sys/wait/waitpid.h"
+#include "src/unistd/execv.h"
+#include "src/unistd/fork.h"
+
+#include "utils/IntegrationTest/test.h"
+
+#include <signal.h>
+#include <sys/wait.h>
+
+void fork_and_execv_normal_exit() {
+ pid_t pid = __llvm_libc::fork();
+ if (pid == 0) {
+ const char *path = "libc_execv_test_normal_exit";
+ char *const argv[] = {
+ const_cast<char *>("execv_test_normal_exit"),
+ nullptr,
+ };
+ __llvm_libc::execv(path, argv);
+ }
+ ASSERT_TRUE(pid > 0);
+ int status;
+ pid_t cpid = __llvm_libc::waitpid(pid, &status, 0);
+ ASSERT_TRUE(cpid > 0);
+ ASSERT_EQ(cpid, pid);
+ ASSERT_TRUE(WIFEXITED(status));
+}
+
+void fork_and_execv_signal_exit() {
+ pid_t pid = __llvm_libc::fork();
+ if (pid == 0) {
+ const char *path = "libc_execv_test_signal_exit";
+ char *const argv[] = {
+ const_cast<char *>("execv_test_normal_exit"),
+ nullptr,
+ };
+ __llvm_libc::execv(path, argv);
+ }
+ ASSERT_TRUE(pid > 0);
+ int status;
+ pid_t cpid = __llvm_libc::waitpid(pid, &status, 0);
+ ASSERT_TRUE(cpid > 0);
+ ASSERT_EQ(cpid, pid);
+ ASSERT_FALSE(WIFEXITED(status));
+ ASSERT_TRUE(WTERMSIG(status) == SIGUSR1);
+}
+
+TEST_MAIN(int argc, char **argv, char **envp) {
+ fork_and_execv_normal_exit();
+ fork_and_execv_signal_exit();
+ return 0;
+}
diff --git a/libc/test/integration/src/unistd/execv_test_normal_exit.cpp b/libc/test/integration/src/unistd/execv_test_normal_exit.cpp
new file mode 100644
index 0000000000000..567bd7d47d838
--- /dev/null
+++ b/libc/test/integration/src/unistd/execv_test_normal_exit.cpp
@@ -0,0 +1,10 @@
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int main() {
+ char *env = getenv("EXECV_TEST");
+ if (env == nullptr)
+ raise(SIGUSR1);
+ return 0;
+}
diff --git a/libc/test/integration/src/unistd/execv_test_signal_exit.cpp b/libc/test/integration/src/unistd/execv_test_signal_exit.cpp
new file mode 100644
index 0000000000000..e266b5c07490f
--- /dev/null
+++ b/libc/test/integration/src/unistd/execv_test_signal_exit.cpp
@@ -0,0 +1,10 @@
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int main() {
+ char *env = getenv("__MISSING_ENV_VAR__");
+ if (env == nullptr)
+ raise(SIGUSR1);
+ return 0;
+}
diff --git a/libc/test/integration/src/unistd/execve_test.cpp b/libc/test/integration/src/unistd/execve_test.cpp
new file mode 100644
index 0000000000000..2b3a846b9bd2c
--- /dev/null
+++ b/libc/test/integration/src/unistd/execve_test.cpp
@@ -0,0 +1,59 @@
+//===-- Unittests for execve ----------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/sys/wait/waitpid.h"
+#include "src/unistd/execve.h"
+#include "src/unistd/fork.h"
+
+#include "utils/IntegrationTest/test.h"
+
+#include <signal.h>
+#include <sys/wait.h>
+
+void fork_and_execv_normal_exit(char **envp) {
+ pid_t pid = __llvm_libc::fork();
+ if (pid == 0) {
+ const char *path = "libc_execv_test_normal_exit";
+ char *const argv[] = {
+ const_cast<char *>("execv_test_normal_exit"),
+ nullptr,
+ };
+ __llvm_libc::execve(path, argv, envp);
+ }
+ ASSERT_TRUE(pid > 0);
+ int status;
+ pid_t cpid = __llvm_libc::waitpid(pid, &status, 0);
+ ASSERT_TRUE(cpid > 0);
+ ASSERT_EQ(cpid, pid);
+ ASSERT_TRUE(WIFEXITED(status));
+}
+
+void fork_and_execv_signal_exit(char **envp) {
+ pid_t pid = __llvm_libc::fork();
+ if (pid == 0) {
+ const char *path = "libc_execv_test_signal_exit";
+ char *const argv[] = {
+ const_cast<char *>("execv_test_normal_exit"),
+ nullptr,
+ };
+ __llvm_libc::execve(path, argv, envp);
+ }
+ ASSERT_TRUE(pid > 0);
+ int status;
+ pid_t cpid = __llvm_libc::waitpid(pid, &status, 0);
+ ASSERT_TRUE(cpid > 0);
+ ASSERT_EQ(cpid, pid);
+ ASSERT_FALSE(WIFEXITED(status));
+ ASSERT_TRUE(WTERMSIG(status) == SIGUSR1);
+}
+
+TEST_MAIN(int argc, char **argv, char **envp) {
+ fork_and_execv_normal_exit(envp);
+ fork_and_execv_signal_exit(envp);
+ return 0;
+}
More information about the libc-commits
mailing list