[libc-commits] [libc] [libc] implement getrandom for windows (PR #119438)

Schrodinger ZHU Yifan via libc-commits libc-commits at lists.llvm.org
Tue Dec 10 11:27:32 PST 2024


https://github.com/SchrodingerZhu created https://github.com/llvm/llvm-project/pull/119438

None

>From 12ad95e64caffc6b2172033878562a40f5e5c955 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Tue, 10 Dec 2024 11:24:00 -0800
Subject: [PATCH] [libc] implement getrandom for windows

---
 libc/config/windows/entrypoints.txt           |  3 +
 libc/config/windows/headers.txt               |  1 +
 libc/hdr/CMakeLists.txt                       |  9 +++
 libc/hdr/sys_random_macros.h                  | 22 ++++++
 libc/hdr/types/CMakeLists.txt                 |  8 +++
 libc/hdr/types/ssize_t.h                      |  3 +-
 libc/include/llvm-libc-types/ssize_t.h        |  6 ++
 libc/src/CMakeLists.txt                       |  2 +-
 libc/src/sys/random/getrandom.h               |  3 +-
 libc/src/sys/random/linux/CMakeLists.txt      |  4 +-
 libc/src/sys/random/windows/CMakeLists.txt    | 14 ++++
 libc/src/sys/random/windows/getrandom.cpp     | 67 +++++++++++++++++++
 libc/test/src/CMakeLists.txt                  |  2 +-
 libc/test/src/sys/random/CMakeLists.txt       | 18 ++++-
 .../sys/random/{linux => }/getrandom_test.cpp |  2 +
 libc/test/src/sys/random/linux/CMakeLists.txt | 15 -----
 16 files changed, 155 insertions(+), 24 deletions(-)
 create mode 100644 libc/hdr/sys_random_macros.h
 create mode 100644 libc/src/sys/random/windows/CMakeLists.txt
 create mode 100644 libc/src/sys/random/windows/getrandom.cpp
 rename libc/test/src/sys/random/{linux => }/getrandom_test.cpp (98%)
 delete mode 100644 libc/test/src/sys/random/linux/CMakeLists.txt

diff --git a/libc/config/windows/entrypoints.txt b/libc/config/windows/entrypoints.txt
index 4ecc3ada9c7682..e615c5fc284f82 100644
--- a/libc/config/windows/entrypoints.txt
+++ b/libc/config/windows/entrypoints.txt
@@ -101,6 +101,9 @@ set(TARGET_LIBC_ENTRYPOINTS
     # time.h entrypoints
     libc.src.time.time
     libc.src.time.clock_getres
+
+    # sys/random.h entrypoints
+    libc.src.sys.random.getrandom
 )
 
 set(TARGET_LIBM_ENTRYPOINTS
diff --git a/libc/config/windows/headers.txt b/libc/config/windows/headers.txt
index bccc04f7697e56..8670dede45df26 100644
--- a/libc/config/windows/headers.txt
+++ b/libc/config/windows/headers.txt
@@ -6,4 +6,5 @@ set(TARGET_PUBLIC_HEADERS
     libc.include.errno
     libc.include.fenv
     libc.include.math
+    libc.include.sys_random
 )
diff --git a/libc/hdr/CMakeLists.txt b/libc/hdr/CMakeLists.txt
index 5eb311f4bb2298..f2396575b06d58 100644
--- a/libc/hdr/CMakeLists.txt
+++ b/libc/hdr/CMakeLists.txt
@@ -189,6 +189,15 @@ add_proxy_header_library(
     libc.include.sys_auxv
 )
 
+add_proxy_header_library(
+  sys_random_macros
+  HDRS
+    sys_random_macros.h
+  FULL_BUILD_DEPENDS
+    libc.include.llvm-libc-macros.sys_random_macros
+    libc.include.sys_random
+)
+
 add_header_library(wchar_overlay HDRS wchar_overlay.h)
 
 add_proxy_header_library(
diff --git a/libc/hdr/sys_random_macros.h b/libc/hdr/sys_random_macros.h
new file mode 100644
index 00000000000000..3c1fce2ca5cc42
--- /dev/null
+++ b/libc/hdr/sys_random_macros.h
@@ -0,0 +1,22 @@
+//===-- Definition of macros from sys/auxv.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_HDR_SYS_RANDOM_MACROS_H
+#define LLVM_LIBC_HDR_SYS_RANDOM_MACROS_H
+
+#if defined(LIBC_FULL_BUILD) || defined(_WIN32)
+
+#include "include/llvm-libc-macros/sys-random-macros.h"
+
+#else // Overlay mode
+
+#include <sys/random.h>
+
+#endif // LLVM_LIBC_FULL_BUILD
+
+#endif // LLVM_LIBC_HDR_SYS_RANDOM_MACROS_H
diff --git a/libc/hdr/types/CMakeLists.txt b/libc/hdr/types/CMakeLists.txt
index 68a0e9603f9752..fcc1776f1e7eda 100644
--- a/libc/hdr/types/CMakeLists.txt
+++ b/libc/hdr/types/CMakeLists.txt
@@ -93,6 +93,14 @@ add_proxy_header_library(
     libc.include.llvm-libc-types.size_t
 )
 
+add_proxy_header_library(
+  ssize_t
+  HDRS
+    ssize_t.h
+  FULL_BUILD_DEPENDS
+    libc.include.llvm-libc-types.ssize_t
+)
+
 add_proxy_header_library(
   mode_t
   HDRS
diff --git a/libc/hdr/types/ssize_t.h b/libc/hdr/types/ssize_t.h
index 4d2000780ee11f..9ebc822434b914 100644
--- a/libc/hdr/types/ssize_t.h
+++ b/libc/hdr/types/ssize_t.h
@@ -8,7 +8,8 @@
 #ifndef LLVM_LIBC_HDR_TYPES_SSIZE_T_H
 #define LLVM_LIBC_HDR_TYPES_SSIZE_T_H
 
-#ifdef LIBC_FULL_BUILD
+// stddef does not provide ssize_t on windows.
+#if defined(LIBC_FULL_BUILD) || defined(_WIN32)
 
 #include "include/llvm-libc-types/ssize_t.h"
 
diff --git a/libc/include/llvm-libc-types/ssize_t.h b/libc/include/llvm-libc-types/ssize_t.h
index 41e4b6d2c500ad..5f2f325753166f 100644
--- a/libc/include/llvm-libc-types/ssize_t.h
+++ b/libc/include/llvm-libc-types/ssize_t.h
@@ -9,6 +9,12 @@
 #ifndef LLVM_LIBC_TYPES_SSIZE_T_H
 #define LLVM_LIBC_TYPES_SSIZE_T_H
 
+// https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types
+#if __has_include(<BaseTsd.h>)
+#include <BaseTsd.h>
+typedef SSIZE_T ssize_t;
+#else
 typedef __INT64_TYPE__ ssize_t;
+#endif
 
 #endif // LLVM_LIBC_TYPES_SSIZE_T_H
diff --git a/libc/src/CMakeLists.txt b/libc/src/CMakeLists.txt
index 9fc331ad18a391..e6ac299f7346e5 100644
--- a/libc/src/CMakeLists.txt
+++ b/libc/src/CMakeLists.txt
@@ -16,7 +16,7 @@ add_subdirectory(strings)
 add_subdirectory(wchar)
 add_subdirectory(time)
 
-if(${LIBC_TARGET_OS} STREQUAL "linux")
+if(${LIBC_TARGET_OS} STREQUAL "linux" OR ${LIBC_TARGET_OS} STREQUAL "windows")
   add_subdirectory(dirent)
   add_subdirectory(fcntl)
   add_subdirectory(pthread)
diff --git a/libc/src/sys/random/getrandom.h b/libc/src/sys/random/getrandom.h
index 134bd0cd9468d8..376ec389e582fb 100644
--- a/libc/src/sys/random/getrandom.h
+++ b/libc/src/sys/random/getrandom.h
@@ -9,8 +9,9 @@
 #ifndef LLVM_LIBC_SRC_SYS_RANDOM_GETRANDOM_H
 #define LLVM_LIBC_SRC_SYS_RANDOM_GETRANDOM_H
 
+#include "hdr/sys_random_macros.h"
+#include "hdr/types/ssize_t.h"
 #include "src/__support/macros/config.h"
-#include <sys/random.h>
 
 namespace LIBC_NAMESPACE_DECL {
 
diff --git a/libc/src/sys/random/linux/CMakeLists.txt b/libc/src/sys/random/linux/CMakeLists.txt
index 474e275ee597a8..dc6506adfc5cd1 100644
--- a/libc/src/sys/random/linux/CMakeLists.txt
+++ b/libc/src/sys/random/linux/CMakeLists.txt
@@ -5,8 +5,8 @@ add_entrypoint_object(
   HDRS
     ../getrandom.h
   DEPENDS
-    libc.include.sys_random
-    libc.include.sys_syscall
+    libc.hdr.sys_random_macros
+    libc.hdr.types.ssize_t
     libc.src.__support.OSUtil.osutil
     libc.src.errno.errno
 )
diff --git a/libc/src/sys/random/windows/CMakeLists.txt b/libc/src/sys/random/windows/CMakeLists.txt
new file mode 100644
index 00000000000000..948b343bb69e88
--- /dev/null
+++ b/libc/src/sys/random/windows/CMakeLists.txt
@@ -0,0 +1,14 @@
+add_entrypoint_object(
+  getrandom
+  SRCS
+    getrandom.cpp
+  HDRS
+    ../getrandom.h
+  DEPENDS
+    # Maybe we should include the following 
+    # but we don't really care the flags on Windows
+    # libc.hdr.sys_random_macros
+    libc.hdr.types.ssize_t
+    libc.src.errno.errno
+    libc.src.__support.CPP.limits
+)
diff --git a/libc/src/sys/random/windows/getrandom.cpp b/libc/src/sys/random/windows/getrandom.cpp
new file mode 100644
index 00000000000000..af5cc2e05edc99
--- /dev/null
+++ b/libc/src/sys/random/windows/getrandom.cpp
@@ -0,0 +1,67 @@
+//===-- Windows 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/CPP/bit.h"
+#include "src/__support/CPP/limits.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/optimization.h"
+#include "src/errno/libc_errno.h"
+
+#define WIN32_LEAN_AND_MEAN
+#define NOMINMAX
+#include <Windows.h>
+#include <bcrypt.h>
+#include <ntstatus.h>
+#pragma comment(lib, "bcrypt.lib")
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(ssize_t, getrandom,
+                   (void *buf, size_t buflen,
+                    [[maybe_unused]] unsigned int flags)) {
+  // https://learn.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom
+  // BCRYPT_USE_SYSTEM_PREFERRED_RNG
+  // Use the system-preferred random number generator algorithm. The hAlgorithm
+  // parameter must be NULL.
+
+  // flags are ignored as Windows does not distinguish between urandom/random.
+  // size_t is larger than ULONG. Linux API allows getrandom to return fewer
+  // bytes than required. Hence, we trancate the size_t to ULONG. If user really
+  // needs huge amount of bytes (which is highly unlikely), they can call
+  // getrandom multiple times in a loop. This is also the common pattern in
+  // Linux.
+
+  // https://learn.microsoft.com/en-us/windows-hardware/drivers/gettingstarted/virtual-address-spaces
+  // A 64-bit process on 64-bit Windows has a virtual address space within the
+  // 128-terabyte range 0x000'00000000 through 0x7FFF'FFFFFFFF.
+  if (buf == nullptr || cpp::bit_cast<INT_PTR>(buf) < 0) {
+    libc_errno = EFAULT;
+    return -1;
+  }
+
+  constexpr size_t PARAM_LIMIT =
+      static_cast<size_t>(cpp::numeric_limits<ULONG>::max());
+  constexpr size_t RETURN_LIMIT =
+      static_cast<size_t>(cpp::numeric_limits<ssize_t>::max());
+  buflen = buflen > PARAM_LIMIT ? PARAM_LIMIT : buflen;
+  buflen = buflen > RETURN_LIMIT ? RETURN_LIMIT : buflen;
+  NTSTATUS result = ::BCryptGenRandom(nullptr, static_cast<PUCHAR>(buf),
+                                      static_cast<ULONG>(buflen),
+                                      BCRYPT_USE_SYSTEM_PREFERRED_RNG);
+
+  // not possible to overflow as we have truncated the limit.
+  if (LIBC_LIKELY(result == STATUS_SUCCESS))
+    return static_cast<ssize_t>(buflen);
+
+  libc_errno = EINVAL;
+  return -1;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/CMakeLists.txt b/libc/test/src/CMakeLists.txt
index 31008508d64928..ee393ed76969a3 100644
--- a/libc/test/src/CMakeLists.txt
+++ b/libc/test/src/CMakeLists.txt
@@ -65,7 +65,7 @@ add_subdirectory(time)
 # Depends on utilities in stdlib
 add_subdirectory(inttypes)
 
-if(${LIBC_TARGET_OS} STREQUAL "linux")
+if(${LIBC_TARGET_OS} STREQUAL "linux" OR ${LIBC_TARGET_OS} STREQUAL "windows")
   add_subdirectory(fcntl)
   add_subdirectory(sched)
   add_subdirectory(sys)
diff --git a/libc/test/src/sys/random/CMakeLists.txt b/libc/test/src/sys/random/CMakeLists.txt
index b4bbe81c92ff2e..c7146c2d478622 100644
--- a/libc/test/src/sys/random/CMakeLists.txt
+++ b/libc/test/src/sys/random/CMakeLists.txt
@@ -1,3 +1,15 @@
-if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
-  add_subdirectory(${LIBC_TARGET_OS})
-endif()
+add_custom_target(libc_sys_random_unittests)
+
+add_libc_unittest(
+  getrandom_test
+  SUITE
+    libc_sys_random_unittests
+  SRCS
+    getrandom_test.cpp
+  DEPENDS
+    libc.hdr.sys_random_macros
+    libc.src.errno.errno
+    libc.src.math.fabs
+    libc.src.sys.random.getrandom
+    libc.test.UnitTest.ErrnoSetterMatcher
+)
diff --git a/libc/test/src/sys/random/linux/getrandom_test.cpp b/libc/test/src/sys/random/getrandom_test.cpp
similarity index 98%
rename from libc/test/src/sys/random/linux/getrandom_test.cpp
rename to libc/test/src/sys/random/getrandom_test.cpp
index e3481b73ca0027..10d0577d05c62e 100644
--- a/libc/test/src/sys/random/linux/getrandom_test.cpp
+++ b/libc/test/src/sys/random/getrandom_test.cpp
@@ -13,12 +13,14 @@
 #include "test/UnitTest/ErrnoSetterMatcher.h"
 #include "test/UnitTest/Test.h"
 
+#ifndef _WIN32
 TEST(LlvmLibcGetRandomTest, InvalidFlag) {
   LIBC_NAMESPACE::cpp::array<char, 10> buffer;
   LIBC_NAMESPACE::libc_errno = 0;
   ASSERT_THAT(LIBC_NAMESPACE::getrandom(buffer.data(), buffer.size(), -1),
               LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails(EINVAL));
 }
+#endif
 
 TEST(LlvmLibcGetRandomTest, InvalidBuffer) {
   LIBC_NAMESPACE::libc_errno = 0;
diff --git a/libc/test/src/sys/random/linux/CMakeLists.txt b/libc/test/src/sys/random/linux/CMakeLists.txt
deleted file mode 100644
index 737326cb158ce5..00000000000000
--- a/libc/test/src/sys/random/linux/CMakeLists.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-add_custom_target(libc_sys_random_unittests)
-
-add_libc_unittest(
-  getrandom_test
-  SUITE
-    libc_sys_random_unittests
-  SRCS
-    getrandom_test.cpp
-  DEPENDS
-    libc.include.sys_random
-    libc.src.errno.errno
-    libc.src.math.fabs
-    libc.src.sys.random.getrandom
-    libc.test.UnitTest.ErrnoSetterMatcher
-)



More information about the libc-commits mailing list