commit:     39a108d58143886c78c76fa1d9000210102624f7
Author:     Kerin Millar <kfm <AT> plushkava <DOT> net>
AuthorDate: Thu Aug  8 23:51:46 2024 +0000
Commit:     Sam James <sam <AT> gentoo <DOT> org>
CommitDate: Sun Aug 11 10:11:01 2024 +0000
URL:        
https://gitweb.gentoo.org/proj/gentoo-functions.git/commit/?id=39a108d5

Handle integer overflow as a special case in _should_throttle()

At the point that the genfun_time variable overflows, guarantee that the
should_throttle() function behaves as if no throttling should occur
rather than proceed to perform arithmetic based on the result of
deducting genfun_last_time from genfun_time.

Further, guarantee that the should_throttle() function behaves as if no
throttling should occur upon the very first occasion that it is called,
provided that the call to update_time() succeeds.

Finally, add a test case.

Signed-off-by: Kerin Millar <kfm <AT> plushkava.net>
Signed-off-by: Sam James <sam <AT> gentoo.org>

 functions.sh   | 22 +++++++++++++++-------
 test-functions | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 62 insertions(+), 7 deletions(-)

diff --git a/functions.sh b/functions.sh
index 78830c6..e7ef6fe 100644
--- a/functions.sh
+++ b/functions.sh
@@ -756,15 +756,25 @@ _select_by_mtime()
 #
 # Considers the first parameter as a number of centiseconds and determines
 # whether fewer have elapsed since the last occasion on which the function was
-# called.
+# called, or whether the last genfun_time update resulted in integer overflow.
 #
 _should_throttle()
 {
        _update_time || return
-       if [ "$(( genfun_time - genfun_last_time > $1 ))" -eq 1 ]; then
-               genfun_last_time=${genfun_time}
-               false
-       fi
+
+       _should_throttle()
+       {
+               _update_time || return
+               if [ "$(( (genfun_time < 0 && genfun_last_time >= 0) || 
genfun_time - genfun_last_time > $1 ))" -eq 1 ]
+               then
+                       genfun_last_time=${genfun_time}
+                       false
+               fi
+
+       }
+
+       genfun_last_time=${genfun_time}
+       false
 }
 
 #
@@ -817,8 +827,6 @@ _update_columns()
 #
 _update_time()
 {
-       genfun_last_time=0
-
        # shellcheck disable=3028
        if [ "${BASH_VERSINFO:-0}" -ge 5 ]; then
                # shellcheck disable=2034,3045

diff --git a/test-functions b/test-functions
index 1f54208..34ffc41 100755
--- a/test-functions
+++ b/test-functions
@@ -1069,6 +1069,52 @@ test_update_time() {
        iterate_tests 3 "$@"
 }
 
+test_should_throttle() {
+       local bits max_int
+
+       genfun_time=
+       bits=30
+       while [ "${bits}" -lt 128 ]; do
+               # Dash is buggy and fails to handle $(( 1 << ++bits )).
+               bits=$(( bits + 1 ))
+               case $(( max_int = 1 << bits )) in
+                       -*)
+                               max_int=$(( max_int - 1 ))
+                               genfun_time=$(( max_int - 4 ))
+                               break
+               esac
+       done
+
+       if [ ! "${genfun_time}" ]; then
+               bailout "Failed to calculate the maximum possible integer value"
+       fi
+
+       # For the first test, genfun_last_time is not yet known. Therefore, the
+       # return value should always be 1. For the fifth test, integer overflow
+       # is expected to occur. Again, the return value should always be 1.
+       set -- \
+               ge  1  "${max_int}" \
+               eq  0  2            \
+               ge  1  1            \
+               ge  1  0            \
+               ge  1  2            \
+               eq  0  2            \
+               ge  1  1            \
+               ge  1  0
+
+       _update_time() {
+               true
+       }
+
+       callback() {
+               shift
+               test_description="_should_throttle $1 (${genfun_time}, $(( 
genfun_time += 1 )))"
+               _should_throttle "$1"
+       }
+
+       iterate_tests 3 "$@"
+}
+
 iterate_tests() {
        local code i j passed slice_width total
 
@@ -1152,6 +1198,7 @@ else
        test_assign || rc=1
        test_deref || rc=1
        test_update_time || rc=1
+       test_should_throttle || rc=1
 fi
 
 cleanup_tmpdir

Reply via email to