diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -113,6 +113,9 @@ 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 diff --git a/libc/config/linux/x86_64/headers.txt b/libc/config/linux/x86_64/headers.txt --- a/libc/config/linux/x86_64/headers.txt +++ b/libc/config/linux/x86_64/headers.txt @@ -12,6 +12,7 @@ libc.include.stdlib libc.include.string libc.include.sys_mman + libc.include.sys_random libc.include.sys_syscall libc.include.threads libc.include.time diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt --- a/libc/include/CMakeLists.txt +++ b/libc/include/CMakeLists.txt @@ -228,6 +228,17 @@ .llvm-libc-macros.sys_mman_macros ) +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 diff --git a/libc/include/llvm-libc-macros/CMakeLists.txt b/libc/include/llvm-libc-macros/CMakeLists.txt --- a/libc/include/llvm-libc-macros/CMakeLists.txt +++ b/libc/include/llvm-libc-macros/CMakeLists.txt @@ -52,6 +52,14 @@ .linux.sys_mman_macros ) +add_header( + sys_random_macros + HDR + sys-random-macros.h + DEPENDS + .linux.sys_random_macros +) + add_header( sys_resource_macros HDR diff --git a/libc/include/llvm-libc-macros/linux/CMakeLists.txt b/libc/include/llvm-libc-macros/linux/CMakeLists.txt --- a/libc/include/llvm-libc-macros/linux/CMakeLists.txt +++ b/libc/include/llvm-libc-macros/linux/CMakeLists.txt @@ -17,9 +17,9 @@ ) add_header( - sys_stat_macros + sys_random_macros HDR - sys-stat-macros.h + sys-random-macros.h ) add_header( @@ -40,6 +40,12 @@ sys-resource-macros.h ) +add_header( + sys_stat_macros + HDR + sys-stat-macros.h +) + add_header( unistd_macros HDR 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 --- /dev/null +++ b/libc/include/llvm-libc-macros/linux/sys-random-macros.h @@ -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 --- /dev/null +++ b/libc/include/llvm-libc-macros/sys-random-macros.h @@ -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 --- /dev/null +++ b/libc/include/sys/random.h.def @@ -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 + +%%public_api() + +#endif // LLVM_LIBC_SYS_RANDOM_H diff --git a/libc/spec/linux.td b/libc/spec/linux.td --- a/libc/spec/linux.td +++ b/libc/spec/linux.td @@ -63,6 +63,28 @@ [Macro<"MAP_ANONYMOUS">] >; + HeaderSpec SysRandom = HeaderSpec< + "sys/random.h", + [ + Macro<"GRND_RANDOM">, + Macro<"GRND_NONBLOCK">, + Macro<"GRND_INSECURE">, + ], + [], // Types + [], // Enumerations + [ + FunctionSpec< + "getrandom", + RetValSpec, + [ + ArgSpec, + ArgSpec, + ArgSpec + ] + >, + ] + >; + HeaderSpec Signal = HeaderSpec< "signal.h", [ @@ -108,6 +130,7 @@ let Headers = [ Errno, SysMMan, + SysRandom, Signal, ]; } diff --git a/libc/src/sys/CMakeLists.txt b/libc/src/sys/CMakeLists.txt --- a/libc/src/sys/CMakeLists.txt +++ b/libc/src/sys/CMakeLists.txt @@ -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 --- /dev/null +++ b/libc/src/sys/random/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( + 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 --- /dev/null +++ b/libc/src/sys/random/getrandom.h @@ -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 + +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 --- /dev/null +++ b/libc/src/sys/random/linux/CMakeLists.txt @@ -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 --- /dev/null +++ b/libc/src/sys/random/linux/getrandom.cpp @@ -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 +#include // 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 diff --git a/libc/test/src/sys/CMakeLists.txt b/libc/test/src/sys/CMakeLists.txt --- a/libc/test/src/sys/CMakeLists.txt +++ b/libc/test/src/sys/CMakeLists.txt @@ -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 --- /dev/null +++ b/libc/test/src/sys/random/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/random/linux/CMakeLists.txt b/libc/test/src/sys/random/linux/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libc/test/src/sys/random/linux/CMakeLists.txt @@ -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 --- /dev/null +++ b/libc/test/src/sys/random/linux/getrandom_test.cpp @@ -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(generator()) / 65536.0; + auto y = static_cast(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); +}