From 3f965818b6a98f4dedba1a5c3517f661c018e62e Mon Sep 17 00:00:00 2001 From: Siva Chandra Reddy Date: Thu, 6 Oct 2022 05:24:18 +0000 Subject: [PATCH] [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 --- libc/cmake/modules/LLVMLibCTestRules.cmake | 6 ++- libc/config/linux/aarch64/entrypoints.txt | 3 ++ libc/config/linux/api.td | 2 +- libc/config/linux/x86_64/entrypoints.txt | 3 ++ libc/include/CMakeLists.txt | 2 + libc/include/llvm-libc-types/CMakeLists.txt | 2 + libc/include/llvm-libc-types/__exec_argv_t.h | 14 +++++ libc/include/llvm-libc-types/__exec_envp_t.h | 14 +++++ libc/loader/linux/aarch64/start.cpp | 4 ++ libc/loader/linux/x86_64/CMakeLists.txt | 2 + libc/loader/linux/x86_64/start.cpp | 4 ++ libc/spec/posix.td | 18 +++++++ libc/src/unistd/CMakeLists.txt | 22 ++++++++ libc/src/unistd/environ.cpp | 14 +++++ libc/src/unistd/environ.h | 18 +++++++ libc/src/unistd/execv.h | 18 +++++++ libc/src/unistd/execve.h | 18 +++++++ libc/src/unistd/linux/CMakeLists.txt | 27 ++++++++++ libc/src/unistd/linux/execv.cpp | 33 ++++++++++++ libc/src/unistd/linux/execve.cpp | 33 ++++++++++++ libc/test/integration/src/unistd/CMakeLists.txt | 62 ++++++++++++++++++++++ libc/test/integration/src/unistd/execv_test.cpp | 59 ++++++++++++++++++++ .../src/unistd/execv_test_normal_exit.cpp | 10 ++++ .../src/unistd/execv_test_signal_exit.cpp | 10 ++++ libc/test/integration/src/unistd/execve_test.cpp | 59 ++++++++++++++++++++ 25 files changed, 454 insertions(+), 3 deletions(-) create mode 100644 libc/include/llvm-libc-types/__exec_argv_t.h create mode 100644 libc/include/llvm-libc-types/__exec_envp_t.h create mode 100644 libc/src/unistd/environ.cpp create mode 100644 libc/src/unistd/environ.h create mode 100644 libc/src/unistd/execv.h create mode 100644 libc/src/unistd/execve.h create mode 100644 libc/src/unistd/linux/execv.cpp create mode 100644 libc/src/unistd/linux/execve.cpp create mode 100644 libc/test/integration/src/unistd/execv_test.cpp create mode 100644 libc/test/integration/src/unistd/execv_test_normal_exit.cpp create mode 100644 libc/test/integration/src/unistd/execv_test_signal_exit.cpp create mode 100644 libc/test/integration/src/unistd/execve_test.cpp diff --git a/libc/cmake/modules/LLVMLibCTestRules.cmake b/libc/cmake/modules/LLVMLibCTestRules.cmake index f1e8c2c..f4f0a70 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 e88068b..92e3cdc 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 01a7814..bf8dd84 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 98106c7..b8e88e0 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 63f9dfe..35336d3 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 b9e87eb..ffce26d 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 0000000..35b687d9 --- /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 0000000..06eb2dd --- /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 7234c2a..b02ea7d 100644 --- a/libc/loader/linux/aarch64/start.cpp +++ b/libc/loader/linux/aarch64/start.cpp @@ -20,6 +20,7 @@ #include #include #include +#include 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(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 fa27ef1..f62ad0a 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 19670fa..6ddb344 100644 --- a/libc/loader/linux/x86_64/start.cpp +++ b/libc/loader/linux/x86_64/start.cpp @@ -19,6 +19,7 @@ #include #include #include +#include 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(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 369455b..69b9732 100644 --- a/libc/spec/posix.td +++ b/libc/spec/posix.td @@ -45,6 +45,9 @@ def ConstStructDirentPtrPtr : ConstType; def StructTimeSpec : NamedType<"struct timespec">; def StructTimeSpecPtr : PtrType; +def ExecArgvT : NamedType<"__exec_argv_t">; +def ExecEnvpT : NamedType<"__exec_envp_t">; + def POSIX : StandardSpec<"POSIX"> { PtrType CharPtr = PtrType; RestrictedPtrType RestrictedCharPtr = RestrictedPtrType; @@ -299,6 +302,8 @@ def POSIX : StandardSpec<"POSIX"> { "unistd.h", [], // Macros [ + ExecArgvT, + ExecEnvpT, OffTType, SSizeTType, SizeTType, @@ -343,6 +348,16 @@ def POSIX : StandardSpec<"POSIX"> { [ArgSpec] >, FunctionSpec< + "execv", + RetValSpec, + [ArgSpec, ArgSpec] + >, + FunctionSpec< + "execve", + RetValSpec, + [ArgSpec, ArgSpec, ArgSpec] + >, + FunctionSpec< "fork", RetValSpec, [ArgSpec] @@ -512,6 +527,9 @@ def POSIX : StandardSpec<"POSIX"> { RetValSpec, [ArgSpec, ArgSpec, ArgSpec] >, + ], + [ + ObjectSpec<"environ", "char **">, ] >; diff --git a/libc/src/unistd/CMakeLists.txt b/libc/src/unistd/CMakeLists.txt index a460b5d..a9d88ee 100644 --- a/libc/src/unistd/CMakeLists.txt +++ b/libc/src/unistd/CMakeLists.txt @@ -59,6 +59,20 @@ add_entrypoint_object( ) 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 DEPENDS @@ -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 0000000..d3f6f4c --- /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 0000000..eb80841 --- /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 0000000..f26a583 --- /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 0000000..48ac78d --- /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 a3f7ef4..3529222 100644 --- a/libc/src/unistd/linux/CMakeLists.txt +++ b/libc/src/unistd/linux/CMakeLists.txt @@ -106,6 +106,33 @@ add_entrypoint_object( ) 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 fsync.cpp diff --git a/libc/src/unistd/linux/execv.cpp b/libc/src/unistd/linux/execv.cpp new file mode 100644 index 0000000..8eef574 --- /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 +#include // 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 0000000..d490f66 --- /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 +#include // 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 338e1ee..23adb29 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 0000000..8df5752 --- /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 +#include + +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("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("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 0000000..567bd7d --- /dev/null +++ b/libc/test/integration/src/unistd/execv_test_normal_exit.cpp @@ -0,0 +1,10 @@ +#include +#include +#include + +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 0000000..e266b5c --- /dev/null +++ b/libc/test/integration/src/unistd/execv_test_signal_exit.cpp @@ -0,0 +1,10 @@ +#include +#include +#include + +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 0000000..2b3a846 --- /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 +#include + +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("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("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; +} -- 2.7.4