* src/factor.c (mulredc2): Add the carry to p1, which is the high word
of a two-word integer created by summing two single-word integers and is
therefore unable to overflow, instead of using a low word r0, which may
wrap around by adding the carry.
* tests/factor/mulredc2-infloop.sh: New file.
* tests/local.mk (all_tests): Add the new test.
* NEWS: Mention the bug fix.

Discovered by Anthropic's OSS Scanner, as bug ANT-2026-CFUR0JKW.
---
 NEWS                             |  4 ++++
 src/factor.c                     |  4 ++--
 tests/factor/mulredc2-infloop.sh | 30 ++++++++++++++++++++++++++++++
 tests/local.mk                   |  1 +
 4 files changed, 37 insertions(+), 2 deletions(-)
 create mode 100755 tests/factor/mulredc2-infloop.sh

diff --git a/NEWS b/NEWS
index b315ce7f4..e5e81191f 100644
--- a/NEWS
+++ b/NEWS
@@ -21,6 +21,10 @@ GNU coreutils NEWS                                    -*- 
outline -*-
   non-space characters, or the number itself when followed by spaces.
   [bugs introduced in coreutils-9.8]
 
+  'factor' no longer infinite loops with certain large numbers, e.g.,
+  146077762747232966952776282887314548659.
+  [bugs introduced in coreutils-8.20]
+
   'fold' no longer prematurely wraps lines with a wide character towards
   the start of a line, followed by multiple backspaces.  Also backspaces
   after a tab character are accounted for correctly.
diff --git a/src/factor.c b/src/factor.c
index e08060cba..7dd22a310 100644
--- a/src/factor.c
+++ b/src/factor.c
@@ -1122,7 +1122,7 @@ mulredc2 (mp_limb_t *r1p,
   q = mi * t0;
   umul_ppmm (p1, p0, q, m0);
   umul_ppmm (s1, s0, q, m1);
-  r0 += (t0 != 0); /* Carry */
+  p1 += (t0 != 0); /* Carry */
   add_ssaaaa (r1, r0, r1, r0, 0, p1);
   add_ssaaaa (r1, r0, r1, r0, 0, t1);
   add_ssaaaa (r1, r0, r1, r0, s1, s0);
@@ -1149,7 +1149,7 @@ mulredc2 (mp_limb_t *r1p,
   add_ssaaaa (r1, r0, s1, s0, 0, r1);
   umul_ppmm (p1, p0, q, m0);
   umul_ppmm (s1, s0, q, m1);
-  r0 += (t0 != 0); /* Carry */
+  p1 += (t0 != 0); /* Carry */
   add_ssaaaa (r1, r0, r1, r0, 0, p1);
   add_ssaaaa (r1, r0, r1, r0, 0, t1);
   add_ssaaaa (r1, r0, r1, r0, s1, s0);
diff --git a/tests/factor/mulredc2-infloop.sh b/tests/factor/mulredc2-infloop.sh
new file mode 100755
index 000000000..1c05ce561
--- /dev/null
+++ b/tests/factor/mulredc2-infloop.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+# Test an invocation that would infinite loop due to a missing
+# overflow check in mulredc2.
+
+# Copyright (C) 2026 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ factor
+
+
+printf '%s: %s %s\n' 146077762747232966952776282887314548659 37853 \
+  3859080198325970648370704643946703 >exp || framework_failure_
+timeout 10 factor 146077762747232966952776282887314548659 >err >out || fail=1
+compare exp out || fail=1
+compare /dev/null err || fail=1
+
+Exit $fail
diff --git a/tests/local.mk b/tests/local.mk
index 7d75b4b5a..3cac910af 100644
--- a/tests/local.mk
+++ b/tests/local.mk
@@ -375,6 +375,7 @@ all_tests =                                 \
   tests/expr/expr-multibyte.pl                 \
   tests/factor/factor.pl                       \
   tests/factor/factor-parallel.sh              \
+  tests/factor/mulredc2-infloop.sh             \
   tests/misc/false-status.sh                   \
   tests/fold/fold-characters.sh                        \
   tests/fold/fold-nbsp.sh                      \
-- 
2.56.0


Reply via email to