commit:     2500778920f533c56fa55798ec8d381276ae84d1
Author:     Kerin Millar <kfm <AT> plushkava <DOT> net>
AuthorDate: Wed Aug  7 17:45:02 2024 +0000
Commit:     Sam James <sam <AT> gentoo <DOT> org>
CommitDate: Sun Aug 11 10:10:57 2024 +0000
URL:        
https://gitweb.gentoo.org/proj/gentoo-functions.git/commit/?id=25007789

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 <AT> plushkava.net>
Signed-off-by: Sam James <sam <AT> gentoo.org>

 functions.sh   | 42 +++++++++++++++++++++++++++++++++++++-----
 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
@@ -415,21 +415,25 @@ test_yesno() {
 
 test_srandom() {
        set -- \
+               eq 0 \
+               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 "$@"
 }
 

Reply via email to