45# include <sys/syscall.h>
48#ifdef HAVE_SYS_PARAM_H
49# include <sys/param.h>
50# if (defined(__FreeBSD__) && __FreeBSD_version > 1200000) || (defined(__DragonFly__) && __DragonFly_version >= 500700) || \
51 (defined(__sun) && defined(HAVE_GETRANDOM)) || (defined(__NetBSD__) && __NetBSD_Version__ >= 1000000000) || defined(__midipix__)
52# include <sys/random.h>
56#ifdef HAVE_COMMONCRYPTO_COMMONRANDOM_H
57# include <CommonCrypto/CommonCryptoError.h>
58# include <CommonCrypto/CommonRandom.h>
61#if __has_feature(memory_sanitizer)
62# include <sanitizer/msan_interface.h>
74 snprintf(errstr, errstr_size,
"Failed to retrieve randomness from the operating system (BCryptGenRandom)");
77#elif defined(HAVE_COMMONCRYPTO_COMMONRANDOM_H)
84 if (CCRandomGenerateBytes(bytes,
size) != kCCSuccess) {
85 snprintf(errstr, errstr_size,
"Failed to retrieve randomness from the operating system (CCRandomGenerateBytes)");
88#elif defined(HAVE_ARC4RANDOM_BUF) && ((defined(__OpenBSD__) && OpenBSD >= 201405) || (defined(__NetBSD__) && __NetBSD_Version__ >= 700000001 && __NetBSD_Version__ < 1000000000) || \
99 arc4random_buf(bytes,
size);
101 size_t read_bytes = 0;
102# if (defined(__linux__) && defined(SYS_getrandom)) || (defined(__FreeBSD__) && __FreeBSD_version >= 1200000) || (defined(__DragonFly__) && __DragonFly_version >= 500700) || \
103 (defined(__sun) && defined(HAVE_GETRANDOM)) || (defined(__NetBSD__) && __NetBSD_Version__ >= 1000000000) || defined(__midipix__)
108 while (read_bytes <
size) {
117 size_t amount_to_read =
size - read_bytes;
121# if defined(__linux__)
122 n = syscall(SYS_getrandom, bytes + read_bytes, amount_to_read, 0);
124 n = getrandom(bytes + read_bytes, amount_to_read, 0);
143# if __has_feature(memory_sanitizer)
145 __msan_unpoison(bytes + read_bytes,
n);
147 read_bytes += (size_t)
n;
150 if (read_bytes <
size) {
151 int fd = zend_atomic_int_load_ex(&random_fd);
156 fd = open(
"/dev/urandom", O_RDONLY);
159 snprintf(errstr, errstr_size,
"Cannot open /dev/urandom: %s", strerror(
errno));
161 snprintf(errstr, errstr_size,
"Cannot open /dev/urandom");
170 !(S_ISNAM(st.st_mode) || S_ISCHR(st.st_mode))
177 snprintf(errstr, errstr_size,
"Error reading from /dev/urandom: %s", strerror(
errno));
179 snprintf(errstr, errstr_size,
"Error reading from /dev/urandom");
184 if (!zend_atomic_int_compare_exchange_ex(&random_fd, &expected,
fd)) {
192 while (read_bytes <
size) {
194 ssize_t
n = read(
fd, bytes + read_bytes,
size - read_bytes);
198 snprintf(errstr, errstr_size,
"Could not gather sufficient random data: %s", strerror(
errno));
200 snprintf(errstr, errstr_size,
"Could not gather sufficient random data");
205 read_bytes += (size_t)
n;
251 if ((umax & (umax - 1)) != 0) {
256 while (trial > limit) {
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_random_bytes_ex(void *bytes, size_t size, char *errstr, size_t errstr_size)
PHPAPI void php_random_csprng_shutdown(void)
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_random_int(zend_long min, zend_long max, zend_long *result, bool should_throw)
ZEND_ATTRIBUTE_NONNULL PHPAPI zend_result php_random_bytes(void *bytes, size_t size, bool should_throw)
PHPAPI zend_class_entry * random_ce_Random_RandomException
PHP_WINUTIL_API int php_win32_get_random_bytes(unsigned char *buf, size_t size)
ZEND_API int zend_atomic_int_exchange(zend_atomic_int *obj, int desired)
struct zend_atomic_int_s zend_atomic_int
#define ZEND_ATOMIC_INT_INITIALIZER(desired)
ZEND_API ZEND_COLD zend_object * zend_throw_exception(zend_class_entry *exception_ce, const char *message, zend_long code)
#define ZEND_ATTRIBUTE_NONNULL
ZEND_RESULT_CODE zend_result