[libc-commits] [libc] [libc] implement prctl (PR #74386)

Schrodinger ZHU Yifan via libc-commits libc-commits at lists.llvm.org
Tue Dec 5 11:41:21 PST 2023


https://github.com/SchrodingerZhu updated https://github.com/llvm/llvm-project/pull/74386

>From 2dff624198413742d90bc8bb2568ce6d31751266 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Mon, 4 Dec 2023 18:26:44 -0500
Subject: [PATCH 1/3] [libc] implement prctl

Implement `prctl` as specified in https://man7.org/linux/man-pages/man2/prctl.2.html.

This patch also includes test cases covering two simple use cases:

1. `PR_GET_NAME/PR_SET_NAME`: where userspace data is passed via arg2.
2. `PR_GET_THP_DISABLE`: where return value is passed via syscal retval.
---
 libc/config/linux/aarch64/entrypoints.txt    |  3 ++
 libc/config/linux/arm/entrypoints.txt        |  3 ++
 libc/config/linux/riscv/entrypoints.txt      |  3 ++
 libc/config/linux/x86_64/entrypoints.txt     |  3 ++
 libc/src/sys/CMakeLists.txt                  |  1 +
 libc/src/sys/prctl/CMakeLists.txt            | 10 +++++
 libc/src/sys/prctl/linux/CMakeLists.txt      | 12 ++++++
 libc/src/sys/prctl/linux/prctl.cpp           | 37 ++++++++++++++++++
 libc/src/sys/prctl/prctl.h                   | 21 ++++++++++
 libc/test/src/sys/CMakeLists.txt             |  1 +
 libc/test/src/sys/prctl/CMakeLists.txt       |  3 ++
 libc/test/src/sys/prctl/linux/CMakeLists.txt | 14 +++++++
 libc/test/src/sys/prctl/linux/prctl_test.cpp | 40 ++++++++++++++++++++
 13 files changed, 151 insertions(+)
 create mode 100644 libc/src/sys/prctl/CMakeLists.txt
 create mode 100644 libc/src/sys/prctl/linux/CMakeLists.txt
 create mode 100644 libc/src/sys/prctl/linux/prctl.cpp
 create mode 100644 libc/src/sys/prctl/prctl.h
 create mode 100644 libc/test/src/sys/prctl/CMakeLists.txt
 create mode 100644 libc/test/src/sys/prctl/linux/CMakeLists.txt
 create mode 100644 libc/test/src/sys/prctl/linux/prctl_test.cpp

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 7a60c44570c4e..60e0e2b29aed3 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -165,6 +165,9 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.sys.wait.wait4
     libc.src.sys.wait.waitpid
 
+    # sys/prctl.h entrypoints
+    libc.src.sys.prctl.prctl
+
     # termios.h entrypoints
     libc.src.termios.cfgetispeed
     libc.src.termios.cfgetospeed
diff --git a/libc/config/linux/arm/entrypoints.txt b/libc/config/linux/arm/entrypoints.txt
index b7783ace90a88..123c7e33377ad 100644
--- a/libc/config/linux/arm/entrypoints.txt
+++ b/libc/config/linux/arm/entrypoints.txt
@@ -92,6 +92,9 @@ set(TARGET_LIBC_ENTRYPOINTS
     # sys/mman.h entrypoints
     libc.src.sys.mman.mmap
     libc.src.sys.mman.munmap
+
+    # sys/prctl.h entrypoints
+    libc.src.sys.prctl.prctl
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 28687ef8e234e..948708e35f45d 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -171,6 +171,9 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.sys.wait.wait4
     libc.src.sys.wait.waitpid
 
+    # sys/prctl.h entrypoints
+    libc.src.sys.prctl.prctl
+
     # termios.h entrypoints
     libc.src.termios.cfgetispeed
     libc.src.termios.cfgetospeed
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 43266e0e5b66e..13b81d3b7ca70 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -174,6 +174,9 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.sys.wait.wait4
     libc.src.sys.wait.waitpid
 
+    # sys/prctl.h entrypoints
+    libc.src.sys.prctl.prctl
+
     # termios.h entrypoints
     libc.src.termios.cfgetispeed
     libc.src.termios.cfgetospeed
diff --git a/libc/src/sys/CMakeLists.txt b/libc/src/sys/CMakeLists.txt
index bf869ddc6a23c..12e2020f013ab 100644
--- a/libc/src/sys/CMakeLists.txt
+++ b/libc/src/sys/CMakeLists.txt
@@ -7,3 +7,4 @@ add_subdirectory(sendfile)
 add_subdirectory(stat)
 add_subdirectory(utsname)
 add_subdirectory(wait)
+add_subdirectory(prctl)
diff --git a/libc/src/sys/prctl/CMakeLists.txt b/libc/src/sys/prctl/CMakeLists.txt
new file mode 100644
index 0000000000000..a78c3c5a40bc0
--- /dev/null
+++ b/libc/src/sys/prctl/CMakeLists.txt
@@ -0,0 +1,10 @@
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+  add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+endif()
+
+add_entrypoint_object(
+  prctl
+  ALIAS
+  DEPENDS
+    .${LIBC_TARGET_OS}.prctl
+)
diff --git a/libc/src/sys/prctl/linux/CMakeLists.txt b/libc/src/sys/prctl/linux/CMakeLists.txt
new file mode 100644
index 0000000000000..05d336441f4d0
--- /dev/null
+++ b/libc/src/sys/prctl/linux/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_entrypoint_object(
+  prctl
+  SRCS
+    prctl.cpp
+  HDRS
+    ../prctl.h
+  DEPENDS
+    libc.include.sys_prctl
+    libc.include.sys_syscall
+    libc.src.__support.OSUtil.osutil
+    libc.src.errno.errno
+)
diff --git a/libc/src/sys/prctl/linux/prctl.cpp b/libc/src/sys/prctl/linux/prctl.cpp
new file mode 100644
index 0000000000000..b68b7621555dc
--- /dev/null
+++ b/libc/src/sys/prctl/linux/prctl.cpp
@@ -0,0 +1,37 @@
+//===---------- Linux implementation of the prctl function ----------------===//
+//
+// 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/prctl/prctl.h"
+
+#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+
+#include "src/errno/libc_errno.h"
+#include <sys/syscall.h> // For syscall numbers.
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(int, prctl,
+                   (int option, unsigned long arg2, unsigned long arg3,
+                    unsigned long arg4, unsigned long arg5)) {
+  long ret =
+      LIBC_NAMESPACE::syscall_impl(SYS_prctl, option, arg2, arg3, arg4, arg5);
+  // The manpage states that "... return the nonnegative values described
+  // above. All other option values return 0 on success. On error,
+  // -1 is returned, and errno is set to indicate the error."
+  // According to the kernel implementation
+  // (https://github.com/torvalds/linux/blob/bee0e7762ad2c6025b9f5245c040fcc36ef2bde8/kernel/sys.c#L2442),
+  // return value from the syscall is set to 0 on default so we do not need to
+  // set the value on success manually.
+  if (ret < 0) {
+    libc_errno = static_cast<int>(-ret);
+    return -1;
+  }
+  return static_cast<int>(ret);
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/sys/prctl/prctl.h b/libc/src/sys/prctl/prctl.h
new file mode 100644
index 0000000000000..baa0676d4254b
--- /dev/null
+++ b/libc/src/sys/prctl/prctl.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for prctl ---------------------------*-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_SYS_PRCTL_PRCTL_H
+#define LLVM_LIBC_SRC_SYS_PRCTL_PRCTL_H
+
+#include <sys/prctl.h>
+
+namespace LIBC_NAMESPACE {
+
+int prctl(int option, unsigned long arg2, unsigned long arg3,
+          unsigned long arg4, unsigned long arg5);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_SYS_PRCTL_PRCTL_H
diff --git a/libc/test/src/sys/CMakeLists.txt b/libc/test/src/sys/CMakeLists.txt
index 5ef97fe817700..a87e77da7d2cd 100644
--- a/libc/test/src/sys/CMakeLists.txt
+++ b/libc/test/src/sys/CMakeLists.txt
@@ -7,3 +7,4 @@ add_subdirectory(socket)
 add_subdirectory(stat)
 add_subdirectory(utsname)
 add_subdirectory(wait)
+add_subdirectory(prctl)
diff --git a/libc/test/src/sys/prctl/CMakeLists.txt b/libc/test/src/sys/prctl/CMakeLists.txt
new file mode 100644
index 0000000000000..b4bbe81c92ff2
--- /dev/null
+++ b/libc/test/src/sys/prctl/CMakeLists.txt
@@ -0,0 +1,3 @@
+if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
+  add_subdirectory(${LIBC_TARGET_OS})
+endif()
diff --git a/libc/test/src/sys/prctl/linux/CMakeLists.txt b/libc/test/src/sys/prctl/linux/CMakeLists.txt
new file mode 100644
index 0000000000000..25e9b8fd8a007
--- /dev/null
+++ b/libc/test/src/sys/prctl/linux/CMakeLists.txt
@@ -0,0 +1,14 @@
+add_custom_target(libc_sys_prctl_unittests)
+
+add_libc_unittest(
+  prctl_test
+  SUITE
+    libc_sys_prctl_unittests
+  SRCS
+    prctl_test.cpp
+  DEPENDS
+    libc.include.sys_prctl
+    libc.include.errno
+    libc.src.sys.prctl.prctl
+    libc.src.errno.errno
+)
diff --git a/libc/test/src/sys/prctl/linux/prctl_test.cpp b/libc/test/src/sys/prctl/linux/prctl_test.cpp
new file mode 100644
index 0000000000000..27758c9c64234
--- /dev/null
+++ b/libc/test/src/sys/prctl/linux/prctl_test.cpp
@@ -0,0 +1,40 @@
+//===-- Unittests for prctl -----------------------------------------------===//
+//
+// 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/errno/libc_errno.h"
+#include "src/sys/prctl/prctl.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include <errno.h>
+#include <sys/prctl.h>
+
+using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
+using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
+
+TEST(LlvmLibcSysPrctlTest, GetSetName) {
+  char name[17];
+  unsigned long name_addr = 0;
+  ASSERT_THAT(LIBC_NAMESPACE::prctl(PR_GET_NAME, name_addr, 0, 0, 0),
+              Fails(EFAULT, -1));
+
+  name_addr = reinterpret_cast<unsigned long>("libc-test");
+  ASSERT_THAT(LIBC_NAMESPACE::prctl(PR_SET_NAME, name_addr, 0, 0, 0),
+              Succeeds());
+
+  name_addr = reinterpret_cast<unsigned long>(name);
+  ASSERT_THAT(LIBC_NAMESPACE::prctl(PR_GET_NAME, name_addr, 0, 0, 0),
+              Succeeds());
+  ASSERT_STREQ(name, "libc-test");
+}
+
+TEST(LlvmLibcSysPrctlTest, GetTHPDisable) {
+  libc_errno = 0;
+  int ret = LIBC_NAMESPACE::prctl(PR_GET_THP_DISABLE, 0, 0, 0, 0);
+  ASSERT_EQ(libc_errno, 0);
+  ASSERT_GE(ret, 0);
+  ASSERT_LE(ret, 1);
+}

>From 971e2b780e696ff90616a627db2b228fd6ab8b55 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Tue, 5 Dec 2023 13:12:54 -0500
Subject: [PATCH 2/3] remove original TODO from prctl.h.def

---
 libc/include/sys/prctl.h.def | 2 --
 1 file changed, 2 deletions(-)

diff --git a/libc/include/sys/prctl.h.def b/libc/include/sys/prctl.h.def
index 3c29719837ca1..0a11543d07296 100644
--- a/libc/include/sys/prctl.h.def
+++ b/libc/include/sys/prctl.h.def
@@ -15,8 +15,6 @@
 // the macros itself.
 #include <linux/prctl.h>
 
-// TODO: Define the prctl macros.
-
 %%public_api()
 
 #endif // LLVM_LIBC_SYS_PRCTL_H

>From fa5b93a45121cfa571e9f8acc45efb0e66a66567 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Tue, 5 Dec 2023 14:41:04 -0500
Subject: [PATCH 3/3] address CR

---
 libc/test/src/sys/prctl/linux/prctl_test.cpp | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/libc/test/src/sys/prctl/linux/prctl_test.cpp b/libc/test/src/sys/prctl/linux/prctl_test.cpp
index 27758c9c64234..3461909846db8 100644
--- a/libc/test/src/sys/prctl/linux/prctl_test.cpp
+++ b/libc/test/src/sys/prctl/linux/prctl_test.cpp
@@ -32,9 +32,13 @@ TEST(LlvmLibcSysPrctlTest, GetSetName) {
 }
 
 TEST(LlvmLibcSysPrctlTest, GetTHPDisable) {
+  // Manually check errno since the return value logic here is not 
+  // covered in ErrnoSetterMatcher.
   libc_errno = 0;
   int ret = LIBC_NAMESPACE::prctl(PR_GET_THP_DISABLE, 0, 0, 0, 0);
   ASSERT_EQ(libc_errno, 0);
-  ASSERT_GE(ret, 0);
-  ASSERT_LE(ret, 1);
+  // PR_GET_THP_DISABLE return (as the function result) the current 
+  // setting of the "THP disable" flag for the calling thread, which
+  // is either 1, if the flag is set; or 0, if it is not.
+  ASSERT_TRUE(ret == 0 || ret == 1);
 }



More information about the libc-commits mailing list