diff options
author | 2024-08-07 18:45:02 +0100 | |
---|---|---|
committer | 2024-08-11 11:10:57 +0100 | |
commit | 2500778920f533c56fa55798ec8d381276ae84d1 (patch) | |
tree | b7596fe43d711ecc1f3aa0a5f1fd245964c17d6f /functions.sh | |
parent | test-functions: check numerical bounds with awk in test_srandom() (diff) | |
download | gentoo-functions-2500778920f533c56fa55798ec8d381276ae84d1.tar.gz gentoo-functions-2500778920f533c56fa55798ec8d381276ae84d1.tar.bz2 gentoo-functions-2500778920f533c56fa55798ec8d381276ae84d1.zip |
Have srandom() employ an upper bound of 2^31-1
In the case of some shells - mksh, at least - the maximum value of an
integer is 2147483647. Such is a consequence of implementing integers as
signed int rather than signed long, even though doing so contravenes the
specification.
Reduce the output range of srandom() so as to be between 0 and
2147483647, rather than 0 and 4294967295. A change of this scope would
normally justify incrementing GENFUN_API_LEVEL but I shall not do so on
this occasion. My rationale is that >=gentoo-functions-1.7 has not yet
had enough exposure for srandom() to be in use by other projects.
Additionally, have test-functions test srandom() 10 times instead of 5.
Signed-off-by: Kerin Millar <kfm@plushkava.net>
Signed-off-by: Sam James <sam@gentoo.org>
Diffstat (limited to 'functions.sh')
-rw-r--r-- | functions.sh | 42 |
1 files changed, 37 insertions, 5 deletions
diff --git a/functions.sh b/functions.sh index b591acb..1c55b3d 100644 --- a/functions.sh +++ b/functions.sh @@ -463,7 +463,10 @@ quote_args() } # -# Generates a random uint32 with the assistance of the kernel CSPRNG. +# Generates a random number between 0 and 2147483647 (2^31-1) with the +# assistance of the kernel CSPRNG. Upon success, the number shall be printed to +# the standard output along with a trailing <newline>. Otherwise, the return +# value shall be greater than 0. # srandom() { @@ -471,14 +474,43 @@ srandom() if [ "${BASH_VERSINFO:-0}" -ge 5 ]; then srandom() { - printf '%d\n' "${SRANDOM}" + printf '%d\n' "$(( SRANDOM >> 1 ))" + } + elif [ -c /dev/urandom ] && [ "$(( 1 << 31 == -2147483648 ))" -eq 1 ]; then + # The shell implements integers as signed int rather than signed + # long, contrary to the specification. Therefore, bit shifting + # cannot be a viable strategy. Instead, use awk to generate a + # number that is immediately within range. + srandom() + { + local hex + + hex=$( + LC_ALL= + LC_CTYPE=C + od -vAn -N256 -tx1 /dev/urandom | awk ' + { + gsub(/[[:space:]]/, "") + hex = hex $0 + } + END { + if (match(hex, /[0-7][[:xdigit:]]{7}/)) { + print substr(hex, RSTART, RLENGTH) + } else { + exit 1 + } + } + ' + ) && + printf '%d\n' "0x${hex}" } elif [ -c /dev/urandom ]; then srandom() { - printf '%d\n' "0x$( - LC_ALL=C od -vAn -N4 -tx1 /dev/urandom | tr -d '[:space:]' - )" + local hex + + hex=$(LC_ALL=C od -vAn -N4 -tx1 /dev/urandom | tr -d '[:space:]') + [ "${hex}" ] && printf '%d\n' "$(( 0x${hex} >> 1 ))" } else warn "srandom: /dev/urandom doesn't exist as a character device" |