diff --git a/builtin-functions/kphp-light/stdlib/math-functions.txt b/builtin-functions/kphp-light/stdlib/math-functions.txt index 6575523813..19226b9806 100644 --- a/builtin-functions/kphp-light/stdlib/math-functions.txt +++ b/builtin-functions/kphp-light/stdlib/math-functions.txt @@ -164,6 +164,8 @@ function levenshtein ($str1 ::: string, $str2 ::: string) ::: int; function lcg_value() ::: float; +function random_bytes($length ::: int) ::: string | false; + /** @kphp-extern-func-info interruptible */ function uniqid ($prefix ::: string = '', $more_entropy ::: bool = false) ::: string; @@ -187,5 +189,3 @@ define('PHP_ROUND_HALF_ODD', 123423146); /** @kphp-extern-func-info stub generation-required */ function random_int($l ::: int, $r ::: int) ::: int | false; -/** @kphp-extern-func-info stub generation-required */ -function random_bytes($length ::: int) ::: string | false; diff --git a/runtime-light/stdlib/math/random-functions.h b/runtime-light/stdlib/math/random-functions.h index ba35d303e2..50e95680c2 100644 --- a/runtime-light/stdlib/math/random-functions.h +++ b/runtime-light/stdlib/math/random-functions.h @@ -15,6 +15,12 @@ #include #include +#if defined(__APPLE__) +#include +#else +#include +#endif + #include "runtime-common/core/runtime-core.h" #include "runtime-common/stdlib/math/random-functions.h" #include "runtime-light/coroutine/task.h" @@ -83,6 +89,15 @@ inline int64_t lcg_modmult(int64_t a, int64_t b, int64_t c, int64_t m, int64_t s return res; } +inline int64_t secure_rand_buf(void* const buf, size_t length) noexcept { +#if defined(__APPLE__) + arc4random_buf(buf, length); + return 0; +#else + return getrandom(buf, length, GRND_NONBLOCK); +#endif +} + // Analogue of unix's `gettimeofday` // Returns seconds elapsed since Epoch, and milliseconds elapsed from the last second. inline std::pair system_seconds_and_micros() noexcept { @@ -126,6 +141,22 @@ inline double f$lcg_value() noexcept { return static_cast(z) * random_impl_::lcg_value_coef; } +inline Optional f$random_bytes(int64_t length) noexcept { + if (length < 1) [[unlikely]] { + kphp::log::warning("argument #1 ($length) must be greater than 0"); + return false; + } + + string str{static_cast(length), false}; + + if (random_impl_::secure_rand_buf(static_cast(str.buffer()), static_cast(length)) == -1) { + kphp::log::warning("source of randomness cannot be found"); + return false; + } + + return str; +} + inline kphp::coro::task f$uniqid(string prefix = string{}, bool more_entropy = false) noexcept { if (!more_entropy) { co_await f$usleep(1); diff --git a/tests/phpt/dl/385_random_bytes.php b/tests/phpt/dl/385_random_bytes.php index 30c0cf3b42..4c5072e823 100644 --- a/tests/phpt/dl/385_random_bytes.php +++ b/tests/phpt/dl/385_random_bytes.php @@ -1,4 +1,4 @@ -@ok php8 k2_skip +@ok php8