]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
nice: clamp the niceness correctly on GNU/Hurd
authorCollin Funk <collin.funk1@gmail.com>
Sun, 9 Nov 2025 04:30:08 +0000 (20:30 -0800)
committerCollin Funk <collin.funk1@gmail.com>
Mon, 10 Nov 2025 02:48:34 +0000 (18:48 -0800)
* NEWS: Mention the bug fix.
* src/nice.c (MIN_ADJUSTMENT): Set to 0 on the Hurd with glibc ≤ 2.42.
(MAX_ADJUSTMENT): Set to (2 * NZERO - 2) on the Hurd with glibc ≤ 2.42.
(main): Clamp the niceness to be greater or equal to MIN_ADJUSTMENT and
less than or equal to MAX_ADJUSTMENT.
* tests/nice/nice.sh: Add some tests for the Hurd's ranges.

NEWS
src/nice.c
tests/nice/nice.sh

diff --git a/NEWS b/NEWS
index 7e7dc6376394116a0e1b1561c6d06d694168d6fa..46df91b621b8ee81896c30403b68c74648d80fec 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -26,6 +26,10 @@ GNU coreutils NEWS                                    -*- outline -*-
   will no longer always set a __CF_USER_TEXT_ENCODING environment variable.
   [bug introduced in coreutils-9.8]
 
+  'nice' now limits the adjusted niceness value to its supported range on
+  GNU/Hurd.
+  [This bug was present in "the beginning".]
+
   'numfmt' no longer reads out-of-bounds memory with trailing blanks in input.
   [bug introduced with numfmt in coreutils-8.21]
 
index 1c3f2a038760229773b4b7118d7d71ebe2cfb75a..1187607c968ac077375e10fdfe570173b815c428 100644 (file)
@@ -167,12 +167,46 @@ main (int argc, char **argv)
       /* If the requested adjustment is outside the valid range,
          silently bring it to just within range; this mimics what
          "setpriority" and "nice" do.  */
+#if (defined __gnu_hurd__                                               \
+     && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 43)))
+      /* GNU/Hurd's nice(2) only supported 0 to (2 * NZERO - 2) niceness
+         until glibc 2.43.  */
+      enum { MIN_ADJUSTMENT = 0, MAX_ADJUSTMENT = 2 * NZERO - 2 };
+#else
       enum { MIN_ADJUSTMENT = 1 - 2 * NZERO, MAX_ADJUSTMENT = 2 * NZERO - 1 };
+#endif
       long int tmp;
       if (LONGINT_OVERFLOW < xstrtol (adjustment_given, nullptr, 10, &tmp, ""))
         error (EXIT_CANCELED, 0, _("invalid adjustment %s"),
                quote (adjustment_given));
+#if (defined __gnu_hurd__                                               \
+     && (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 43)))
+      /* GNU/Hurd's nice(2) also did not clamp the new niceness into the
+         supported range until glibc 2.43.
+         See <https://sourceware.org/PR33614>.  */
+      errno = 0;
+      current_niceness = GET_NICENESS ();
+      if (current_niceness == -1 && errno != 0)
+        error (EXIT_CANCELED, errno, _("cannot get niceness"));
+      if (tmp < 0)
+        {
+          int sum;
+          if (ckd_add (&sum, current_niceness, tmp) || sum < MIN_ADJUSTMENT)
+            adjustment = MIN_ADJUSTMENT - current_niceness;
+          else
+            adjustment = tmp;
+        }
+      else
+        {
+          int sum;
+          if (ckd_add (&sum, current_niceness, tmp) || MAX_ADJUSTMENT < sum)
+            adjustment = MAX_ADJUSTMENT - current_niceness;
+          else
+            adjustment = tmp;
+        }
+#else
       adjustment = MAX (MIN_ADJUSTMENT, MIN (tmp, MAX_ADJUSTMENT));
+#endif
     }
 
   if (i == argc)
index 7e274ca0d2703efc5f1d9e02d85d8fc73e4dd6d7..70be3eb98c1c160e5f3cdef98817e3aeaf42e3b5 100755 (executable)
@@ -18,6 +18,7 @@
 
 . "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
 print_ver_ nice
+getlimits_
 
 tests='
 0 empty 10
@@ -71,16 +72,45 @@ done
 
 # Test negative niceness - command must be run whether or not change happens.
 if test x$(nice -n -1 nice 2> /dev/null) = x0 ; then
-  # unprivileged user - warn about failure to change
-  nice -n -1 true 2> err || fail=1
-  compare /dev/null err && fail=1
-  mv err exp || framework_failure_
-  nice --1 true 2> err || fail=1
-  compare exp err || fail=1
-  # Failure to write advisory message is fatal.  Buggy through coreutils 8.0.
-  if test -w /dev/full && test -c /dev/full; then
-    returns_ 125 nice -n -1 nice > out 2> /dev/full || fail=1
-    compare /dev/null out || fail=1
+  # GNU/Hurd does not allow negative niceness even if we are a privileged user.
+  if test "$(uname)" = GNU; then
+    max_nice=$(nice -n "$INT_MAX" nice) || framework_failure_
+    # Check that the lowest niceness is 0.
+    nice -n -1 nice > out || fail=1
+    echo '0' > exp || framework_failure_
+    compare exp out || fail=1
+    # Exceeding the max niceness would lead to the program not being executed on
+    # GNU/Hurd with coreutils 9.8 and earlier.
+    nice -n $(("$max_nice" + 1)) nice > out || fail=1
+    echo "$max_nice" > exp || framework_failure_
+    compare exp out || fail=1
+    # GNU/Hurd's nice(2) with glibc 2.42 and earlier does not clamp the
+    # niceness to the supported range.  Check that we workaround the bug.
+    # See <https://sourceware.org/PR33614>.
+    nice -n 1 nice -n $(("$max_nice" - 2)) nice > out|| fail=1
+    echo $(("$max_nice" - 1)) > exp || framework_failure_
+    compare exp out || fail=1
+    nice -n 1 nice -n $(("$max_nice" + 1)) nice > out || fail=1
+    echo "$max_nice" > exp || framework_failure_
+    compare exp out || fail=1
+    nice -n 2 nice -n -1 nice > out || fail=1
+    echo '1' > exp || framework_failure_
+    compare exp out || fail=1
+    nice -n 2 nice -n -3 nice > out || fail=1
+    echo '0' > exp || framework_failure_
+    compare exp out || fail=1
+  else
+    # unprivileged user - warn about failure to change
+    nice -n -1 true 2> err || fail=1
+    compare /dev/null err && fail=1
+    mv err exp || framework_failure_
+    nice --1 true 2> err || fail=1
+    compare exp err || fail=1
+    # Failure to write advisory message is fatal.  Buggy through coreutils 8.0.
+    if test "$(uname)" != GNU && test -w /dev/full && test -c /dev/full; then
+      returns_ 125 nice -n -1 nice > out 2> /dev/full || fail=1
+      compare /dev/null out || fail=1
+    fi
   fi
 else
   # superuser - change succeeds