Implement `getrandom` function for linux targets.
authorSchrodinger ZHU Yifan <yifanzhu@rochester.edu>
Mon, 10 Oct 2022 18:00:13 +0000 (11:00 -0700)
committerMichael Jones <michaelrj@google.com>
Mon, 10 Oct 2022 18:00:35 +0000 (11:00 -0700)
Reviewed By: michaelrj, sivachandra

Differential Revision: https://reviews.llvm.org/D134665

18 files changed:
libc/config/linux/x86_64/entrypoints.txt
libc/config/linux/x86_64/headers.txt
libc/include/CMakeLists.txt
libc/include/llvm-libc-macros/CMakeLists.txt
libc/include/llvm-libc-macros/linux/CMakeLists.txt
libc/include/llvm-libc-macros/linux/sys-random-macros.h [new file with mode: 0644]
libc/include/llvm-libc-macros/sys-random-macros.h [new file with mode: 0644]
libc/include/sys/random.h.def [new file with mode: 0644]
libc/spec/linux.td
libc/src/sys/CMakeLists.txt
libc/src/sys/random/CMakeLists.txt [new file with mode: 0644]
libc/src/sys/random/getrandom.h [new file with mode: 0644]
libc/src/sys/random/linux/CMakeLists.txt [new file with mode: 0644]
libc/src/sys/random/linux/getrandom.cpp [new file with mode: 0644]
libc/test/src/sys/CMakeLists.txt
libc/test/src/sys/random/CMakeLists.txt [new file with mode: 0644]
libc/test/src/sys/random/linux/CMakeLists.txt [new file with mode: 0644]
libc/test/src/sys/random/linux/getrandom_test.cpp [new file with mode: 0644]

index 9874cb8..7e5fde3 100644 (file)
@@ -113,6 +113,9 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.sys.mman.munmap
     libc.src.sys.mman.posix_madvise
 
+    # sys/random.h entrypoints
+    libc.src.sys.random.getrandom
+
     # sys/resource.h entrypoints
     libc.src.sys.resource.getrlimit
     libc.src.sys.resource.setrlimit
index 302d3f8..284f964 100644 (file)
@@ -12,6 +12,7 @@ set(TARGET_PUBLIC_HEADERS
     libc.include.stdlib
     libc.include.string
     libc.include.sys_mman
+    libc.include.sys_random
     libc.include.sys_syscall
     libc.include.threads
     libc.include.time
index d8b92e2..d30009e 100644 (file)
@@ -229,6 +229,17 @@ add_gen_header(
 )
 
 add_gen_header(
+  sys_random
+  DEF_FILE sys/random.h.def
+  GEN_HDR sys/random.h
+  DEPENDS
+    .llvm_libc_common_h
+    .llvm-libc-macros.sys_random_macros
+    .llvm-libc-types.ssize_t
+    .llvm-libc-types.size_t
+)
+
+add_gen_header(
   sys_resource
   DEF_FILE sys/resource.h.def
   GEN_HDR sys/resource.h
index dc20602..def26a1 100644 (file)
@@ -53,6 +53,14 @@ add_header(
 )
 
 add_header(
+  sys_random_macros
+  HDR
+    sys-random-macros.h
+  DEPENDS
+    .linux.sys_random_macros
+)
+
+add_header(
   sys_resource_macros
   HDR
     sys-resource-macros.h
index 8b8e58d..e3c9392 100644 (file)
@@ -17,9 +17,9 @@ add_header(
 )
 
 add_header(
-  sys_stat_macros
+  sys_random_macros
   HDR
-    sys-stat-macros.h
+    sys-random-macros.h
 )
 
 add_header(
@@ -41,6 +41,12 @@ add_header(
 )
 
 add_header(
+  sys_stat_macros
+  HDR
+    sys-stat-macros.h
+)
+
+add_header(
   unistd_macros
   HDR
     unistd-macros.h
diff --git a/libc/include/llvm-libc-macros/linux/sys-random-macros.h b/libc/include/llvm-libc-macros/linux/sys-random-macros.h
new file mode 100644 (file)
index 0000000..1337f8b
--- /dev/null
@@ -0,0 +1,17 @@
+//===-- Definition of macros from sys/random.h ----------------------------===//
+//
+// 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_MACROS_LINUX_SYS_RANDOM_MACROS_H
+#define __LLVM_LIBC_MACROS_LINUX_SYS_RANDOM_MACROS_H
+
+// Getrandom flags
+#define GRND_RANDOM 0x0001
+#define GRND_NONBLOCK 0x0002
+#define GRND_INSECURE 0x0004
+
+#endif // __LLVM_LIBC_MACROS_LINUX_SYS_RANDOM_MACROS_H
diff --git a/libc/include/llvm-libc-macros/sys-random-macros.h b/libc/include/llvm-libc-macros/sys-random-macros.h
new file mode 100644 (file)
index 0000000..4e59efc
--- /dev/null
@@ -0,0 +1,16 @@
+//===-- Macros defined in sys/random.h header file ------------------------===//
+//
+// 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_MACROS_SYS_RANDOM_MACROS_H
+#define __LLVM_LIBC_MACROS_SYS_RANDOM_MACROS_H
+
+#ifdef __unix__
+#include "linux/sys-random-macros.h"
+#endif
+
+#endif // __LLVM_LIBC_MACROS_SYS_RANDOM_MACROS_H
diff --git a/libc/include/sys/random.h.def b/libc/include/sys/random.h.def
new file mode 100644 (file)
index 0000000..b767f24
--- /dev/null
@@ -0,0 +1,18 @@
+//===-- Linux sys/random.h ------------------------------------------------===//
+//
+// 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_SYS_RANDOM_H
+#define LLVM_LIBC_SYS_RANDOM_H
+
+#include <__llvm-libc-common.h>
+
+#include <llvm-libc-macros/sys-random-macros.h>
+
+%%public_api()
+
+#endif // LLVM_LIBC_SYS_RANDOM_H
index 29baf8b..da6ceae 100644 (file)
@@ -63,6 +63,28 @@ def Linux : StandardSpec<"Linux"> {
       [Macro<"MAP_ANONYMOUS">]
   >;
 
+  HeaderSpec SysRandom = HeaderSpec<
+      "sys/random.h",
+      [
+        Macro<"GRND_RANDOM">,
+        Macro<"GRND_NONBLOCK">,
+        Macro<"GRND_INSECURE">,
+      ],
+      [], // Types
+      [], // Enumerations
+      [
+        FunctionSpec<
+          "getrandom",
+          RetValSpec<SSizeTType>,
+          [
+            ArgSpec<VoidPtr>,
+            ArgSpec<SizeTType>,
+            ArgSpec<UnsignedIntType>
+          ]
+        >,
+      ]
+  >;
+
   HeaderSpec Signal = HeaderSpec<
       "signal.h",
       [
@@ -108,6 +130,7 @@ def Linux : StandardSpec<"Linux"> {
   let Headers = [
     Errno,
     SysMMan,
+    SysRandom,
     Signal,
   ];
 }
index f8e25cc..bf6283d 100644 (file)
@@ -1,4 +1,5 @@
 add_subdirectory(mman)
+add_subdirectory(random)
 add_subdirectory(resource)
 add_subdirectory(sendfile)
 add_subdirectory(stat)
diff --git a/libc/src/sys/random/CMakeLists.txt b/libc/src/sys/random/CMakeLists.txt
new file mode 100644 (file)
index 0000000..2291a86
--- /dev/null
@@ -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(
+  getrandom
+  ALIAS
+  DEPENDS
+    .${LIBC_TARGET_OS}.getrandom
+)
diff --git a/libc/src/sys/random/getrandom.h b/libc/src/sys/random/getrandom.h
new file mode 100644 (file)
index 0000000..dab508d
--- /dev/null
@@ -0,0 +1,20 @@
+//===-- Implementation header for getrandom ----------------------*- 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_RANDOM_GETRANDOM_H
+#define LLVM_LIBC_SRC_SYS_RANDOM_GETRANDOM_H
+
+#include <sys/types.h>
+
+namespace __llvm_libc {
+
+ssize_t getrandom(void *buf, size_t buflen, unsigned int flags);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_SYS_RANDOM_GETRANDOM_H
diff --git a/libc/src/sys/random/linux/CMakeLists.txt b/libc/src/sys/random/linux/CMakeLists.txt
new file mode 100644 (file)
index 0000000..474e275
--- /dev/null
@@ -0,0 +1,12 @@
+add_entrypoint_object(
+  getrandom
+  SRCS
+    getrandom.cpp
+  HDRS
+    ../getrandom.h
+  DEPENDS
+    libc.include.sys_random
+    libc.include.sys_syscall
+    libc.src.__support.OSUtil.osutil
+    libc.src.errno.errno
+)
diff --git a/libc/src/sys/random/linux/getrandom.cpp b/libc/src/sys/random/linux/getrandom.cpp
new file mode 100644 (file)
index 0000000..e9c33da
--- /dev/null
@@ -0,0 +1,29 @@
+//===-- Linux implementation of getrandom ---------------------------------===//
+//
+// 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/random/getrandom.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(ssize_t, getrandom,
+                   (void *buf, size_t buflen, unsigned int flags)) {
+  long ret = __llvm_libc::syscall_impl(SYS_getrandom, buf, buflen, flags);
+  if (ret < 0) {
+    errno = -ret;
+    return -1;
+  }
+  return 0;
+}
+
+} // namespace __llvm_libc
index f8e25cc..bf6283d 100644 (file)
@@ -1,4 +1,5 @@
 add_subdirectory(mman)
+add_subdirectory(random)
 add_subdirectory(resource)
 add_subdirectory(sendfile)
 add_subdirectory(stat)
diff --git a/libc/test/src/sys/random/CMakeLists.txt b/libc/test/src/sys/random/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b4bbe81
--- /dev/null
@@ -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/random/linux/CMakeLists.txt b/libc/test/src/sys/random/linux/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3dcfd86
--- /dev/null
@@ -0,0 +1,17 @@
+add_libc_testsuite(libc_sys_random_unittests)
+
+add_libc_unittest(
+  getrandom_test
+  SUITE
+    libc_sys_random_unittests
+  SRCS
+    getrandom_test.cpp
+  DEPENDS
+    libc.include.errno
+    libc.include.math
+    libc.include.sys_random
+    libc.src.errno.errno
+    libc.src.math.fabs
+    libc.src.sys.random.getrandom
+    libc.test.errno_setter_matcher
+)
diff --git a/libc/test/src/sys/random/linux/getrandom_test.cpp b/libc/test/src/sys/random/linux/getrandom_test.cpp
new file mode 100644 (file)
index 0000000..669f197
--- /dev/null
@@ -0,0 +1,47 @@
+#include "src/math/fabs.h"
+#include "src/sys/random/getrandom.h"
+#include "test/ErrnoSetterMatcher.h"
+#include "utils/UnitTest/Test.h"
+
+TEST(LlvmLibcGetRandomTest, InvalidFlag) {
+  using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
+  static constexpr size_t SIZE = 256;
+  char data[SIZE];
+  errno = 0;
+  ASSERT_THAT(__llvm_libc::getrandom(data, SIZE, -1), Fails(EINVAL));
+  errno = 0;
+}
+
+TEST(LlvmLibcGetRandomTest, InvalidBuffer) {
+  using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
+
+  errno = 0;
+  ASSERT_THAT(__llvm_libc::getrandom(nullptr, 65536, 0), Fails(EFAULT));
+  errno = 0;
+}
+
+TEST(LlvmLibcGetRandomTest, PiEstimation) {
+  static constexpr size_t LIMIT = 10000000;
+  static constexpr double PI = 3.14159265358979;
+
+  auto generator = []() {
+    uint16_t data;
+    __llvm_libc::getrandom(&data, sizeof(data), 0);
+    return data;
+  };
+
+  auto sample = [&]() {
+    auto x = static_cast<double>(generator()) / 65536.0;
+    auto y = static_cast<double>(generator()) / 65536.0;
+    return x * x + y * y < 1.0;
+  };
+
+  double counter = 0;
+  for (size_t i = 0; i < LIMIT; ++i) {
+    if (sample()) {
+      counter += 1.0;
+    }
+  }
+  counter = counter / LIMIT * 4.0;
+  ASSERT_TRUE(__llvm_libc::fabs(counter - PI) < 0.1);
+}