[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