Collin Funk <[email protected]> writes:

> That test program assumes that nice() does not clamp the niceness to the
> supported range as it is supposed to [1]. This is the case on GNU/Hurd,
> so I will submit a bug report for that later.
>
> The output is the same on a normal and privileged user:
>
>     $ gcc main.c ./a.out 
>     starting nice: 0
>     minimum nice: 0
>     maximum nice: 38
>     minimum errno: EPERM
>     maximum errno: ESRCH
>
> This patch clamps it to the supported range and adds some tests. Here is
> the corrected behavior:
>
>     $ ./src/nice -n +100 ./src/nice
>     38

Actually my original patch did not work if 'nice' was invoked with a
niceness greater than zero. This v2 patch fixes that and adds more
tests.

Collin

>From 40a9af197767c1a2b4bb2cc4a87f15dad581efa5 Mon Sep 17 00:00:00 2001
Message-ID: <40a9af197767c1a2b4bb2cc4a87f15dad581efa5.1762672551.git.collin.fu...@gmail.com>
From: Collin Funk <[email protected]>
Date: Sat, 8 Nov 2025 20:30:08 -0800
Subject: [PATCH v2] nice: clamp the niceness correctly on GNU/Hurd

* NEWS: Mention the bug fix.
* src/nice.c (MIN_ADJUSTMENT): Set to 0 on the Hurd.
(MAX_ADJUSTMENT): Set to 38 on the Hurd.
(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               |  4 ++++
 src/nice.c         | 30 ++++++++++++++++++++++++++++++
 tests/nice/nice.sh | 46 ++++++++++++++++++++++++++++++++++++----------
 3 files changed, 70 insertions(+), 10 deletions(-)

diff --git a/NEWS b/NEWS
index 7e7dc6376..46df91b62 100644
--- 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]
 
diff --git a/src/nice.c b/src/nice.c
index 1c3f2a038..803e0c017 100644
--- a/src/nice.c
+++ b/src/nice.c
@@ -167,12 +167,42 @@ 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.  */
+#ifdef __gnu_hurd__
+      /* GNU/Hurd's range is 0 to 38.  */
+      enum { MIN_ADJUSTMENT = 0, MAX_ADJUSTMENT = 38 };
+#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));
+#ifdef __gnu_hurd__
+      /* GNU/Hurd's nice(2) does not clamp the given value to the supported
+         range.  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)
diff --git a/tests/nice/nice.sh b/tests/nice/nice.sh
index 7e274ca0d..2133fa519 100755
--- a/tests/nice/nice.sh
+++ b/tests/nice/nice.sh
@@ -71,16 +71,42 @@ 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 privileged user.
+  if test "$(uname)" = GNU; then
+    # Check that the lowest niceness is 0.
+    nice -n -1 nice > out || fail=1
+    echo '0' > exp || framework_failure_
+    compare exp out || fail=1
+    # Check that the highest niceness is 38.
+    nice -n 39 nice > out || fail=1
+    echo '38' > exp || framework_failure_
+    compare exp out || fail=1
+    # GNU/Hurd's nice(2) does not clamp the given value to the supported range.
+    # Check that we workaround the bug.  See <https://sourceware.org/PR33614>.
+    nice -n 1 nice -n 36 nice > out|| fail=1
+    echo '37' > exp || framework_failure_
+    compare exp out || fail=1
+    nice -n 1 nice -n 38 nice > out || fail=1
+    echo '38' > 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
-- 
2.51.1

Reply via email to