Bug 1649121: part 50) Add members for start and end. r=masayuki
[gecko.git] / mfbt / RandomNum.cpp
blobc3bb9ecef4441be2a98d72c63c82085ffd19a638
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
7 #include "mozilla/RandomNum.h"
9 #include <fcntl.h>
10 #ifdef XP_UNIX
11 # include <unistd.h>
12 #endif
14 #if defined(XP_WIN)
16 // Microsoft doesn't "officially" support using RtlGenRandom() directly
17 // anymore, and the Windows headers assume that __stdcall is
18 // the default calling convention (which is true when Microsoft uses this
19 // function to build their own CRT libraries).
21 // We will explicitly declare it with the proper calling convention.
23 # include "minwindef.h"
24 # define RtlGenRandom SystemFunction036
25 extern "C" BOOLEAN NTAPI RtlGenRandom(PVOID RandomBuffer,
26 ULONG RandomBufferLength);
28 #endif
30 #if defined(ANDROID) || defined(XP_DARWIN) || defined(__DragonFly__) || \
31 defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
32 # include <stdlib.h>
33 # define USE_ARC4RANDOM
34 #endif
36 #if defined(__linux__)
37 # include <linux/random.h> // For GRND_NONBLOCK.
38 # include <sys/syscall.h> // For SYS_getrandom.
40 // Older glibc versions don't define SYS_getrandom, so we define it here if
41 // it's not available. See bug 995069.
42 # if defined(__x86_64__)
43 # define GETRANDOM_NR 318
44 # elif defined(__i386__)
45 # define GETRANDOM_NR 355
46 # elif defined(__aarch64__)
47 # define GETRANDOM_NR 278
48 # elif defined(__arm__)
49 # define GETRANDOM_NR 384
50 # elif defined(__powerpc__)
51 # define GETRANDOM_NR 359
52 # elif defined(__s390__)
53 # define GETRANDOM_NR 349
54 # elif defined(__mips__)
55 # include <sgidefs.h>
56 # if _MIPS_SIM == _MIPS_SIM_ABI32
57 # define GETRANDOM_NR 4353
58 # elif _MIPS_SIM == _MIPS_SIM_ABI64
59 # define GETRANDOM_NR 5313
60 # elif _MIPS_SIM == _MIPS_SIM_NABI32
61 # define GETRANDOM_NR 6317
62 # endif
63 # endif
65 # if defined(SYS_getrandom)
66 // We have SYS_getrandom. Use it to check GETRANDOM_NR. Only do this if we set
67 // GETRANDOM_NR so tier 3 platforms with recent glibc are not forced to define
68 // it for no good reason.
69 # if defined(GETRANDOM_NR)
70 static_assert(GETRANDOM_NR == SYS_getrandom,
71 "GETRANDOM_NR should match the actual SYS_getrandom value");
72 # endif
73 # else
74 # define SYS_getrandom GETRANDOM_NR
75 # endif
77 # if defined(GRND_NONBLOCK)
78 static_assert(GRND_NONBLOCK == 1,
79 "If GRND_NONBLOCK is not 1 the #define below is wrong");
80 # else
81 # define GRND_NONBLOCK 1
82 # endif
84 #endif // defined(__linux__)
86 namespace mozilla {
89 * Note - Bug 1500115 has been opened to discuss simplifying or improving
90 * this function in the future; however, the function is secure as-is right
91 * now. Further improvements may be made to reduce complexity, improve
92 * robustness, or take advantage of OS-specific API improvements as they
93 * become available.
97 MFBT_API Maybe<uint64_t> RandomUint64() {
98 #if defined(XP_WIN)
100 uint64_t result = 0;
101 if (!RtlGenRandom(&result, sizeof(result))) {
102 return Nothing();
105 return Some(result);
107 #elif defined(USE_ARC4RANDOM) // defined(XP_WIN)
109 return Some((static_cast<uint64_t>(arc4random()) << 32) | arc4random());
111 #elif defined(XP_UNIX) // defined(USE_ARC4RANDOM)
113 uint64_t result = 0;
115 # if defined(__linux__)
117 long bytesGenerated =
118 syscall(SYS_getrandom, &result, sizeof(result), GRND_NONBLOCK);
120 if ((bytesGenerated > 0) &&
121 (static_cast<unsigned long>(bytesGenerated) == sizeof(result))) {
122 return Some(result);
125 // Fall-through to UNIX behavior if failed
127 # endif // defined(__linux__)
129 int fd = open("/dev/urandom", O_RDONLY);
130 if (fd < 0) {
131 return Nothing();
134 ssize_t bytesRead = read(fd, &result, sizeof(result));
136 close(fd);
138 if (bytesRead < 0) {
139 return Nothing();
142 if (static_cast<size_t>(bytesRead) != sizeof(result)) {
143 return Nothing();
146 return Some(result);
148 #else // defined(XP_UNIX)
149 # error "Platform needs to implement RandomUint64()"
150 #endif
153 MFBT_API uint64_t RandomUint64OrDie() {
154 Maybe<uint64_t> maybeRandomNum = RandomUint64();
156 MOZ_RELEASE_ASSERT(maybeRandomNum.isSome());
158 return maybeRandomNum.value();
161 } // namespace mozilla