diff options
author | Kerin Millar <kfm@plushkava.net> | 2024-08-07 18:45:02 +0100 |
---|---|---|
committer | Sam James <sam@gentoo.org> | 2024-08-11 11:10:57 +0100 |
commit | 2500778920f533c56fa55798ec8d381276ae84d1 (patch) | |
tree | b7596fe43d711ecc1f3aa0a5f1fd245964c17d6f | |
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>
-rw-r--r-- | functions.sh | 42 | ||||
-rwxr-xr-x | test-functions | 12 |
2 files changed, 45 insertions, 9 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" diff --git a/test-functions b/test-functions index 4b2f7f9..96781f2 100755 --- a/test-functions +++ b/test-functions @@ -419,17 +419,21 @@ test_srandom() { eq 0 \ eq 0 \ eq 0 \ + eq 0 \ + eq 0 \ + eq 0 \ + eq 0 \ + eq 0 \ eq 0 - row=0 - callback() { number=$(srandom) - test_description="srandom ($(( row += 1 ))/5: ${number:-blank})" + test_description="srandom ($(( row += 1 ))/10: ${number:-blank})" is_int "${number}" \ - && awk -v "n=${number}" 'BEGIN { exit !(n >= 0 && n <= 4294967295) }' + && awk -v "n=${number}" 'BEGIN { exit !(n >= 0 && n <= 2147483647) }' } + row=0 iterate_tests 2 "$@" } |