nice: clamp the niceness correctly on GNU/Hurd

* 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.
This commit is contained in:
Collin Funk 2025-11-08 20:30:08 -08:00
parent 56fc0e6f8d
commit fc93a44bbe
3 changed files with 78 additions and 10 deletions

4
NEWS
View File

@ -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]

View 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)

View File

@ -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