From 60b9fa995d1b0e8cbb0b1825d37221280cee940d Mon Sep 17 00:00:00 2001 From: Robert Stupp Date: Thu, 16 Jul 2026 10:24:45 +0200 Subject: [PATCH] Use unsigned arithmetic for uint division CEL uint values above Long.MAX_VALUE are stored in signed long slots, so Java signed / and % produced incorrect results for high unsigned operands. Use Long.divideUnsigned() and Long.remainderUnsigned(), and cover high-bit operands in uint division and modulo tests. --- .../java/org/projectnessie/cel/common/types/UintT.java | 4 ++-- .../java/org/projectnessie/cel/common/types/UintTest.java | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/projectnessie/cel/common/types/UintT.java b/core/src/main/java/org/projectnessie/cel/common/types/UintT.java index 04d88528..10e6bcab 100644 --- a/core/src/main/java/org/projectnessie/cel/common/types/UintT.java +++ b/core/src/main/java/org/projectnessie/cel/common/types/UintT.java @@ -249,7 +249,7 @@ public Val divide(Val other) { if (otherInt == 0L) { return divideByZero(); } - return uintOf(i / otherInt); + return uintOf(Long.divideUnsigned(i, otherInt)); } /** Modulo implements traits.Modder.Modulo. */ @@ -262,7 +262,7 @@ public Val modulo(Val other) { if (otherInt == 0L) { return modulusByZero(); } - return uintOf(i % otherInt); + return uintOf(Long.remainderUnsigned(i, otherInt)); } /** Multiply implements traits.Multiplier.Multiply. */ diff --git a/core/src/test/java/org/projectnessie/cel/common/types/UintTest.java b/core/src/test/java/org/projectnessie/cel/common/types/UintTest.java index 4622b39d..96462232 100644 --- a/core/src/test/java/org/projectnessie/cel/common/types/UintTest.java +++ b/core/src/test/java/org/projectnessie/cel/common/types/UintTest.java @@ -164,6 +164,9 @@ void uintConvertToType() { @Test void uintDivide() { assertThat(uintOf(3).divide(uintOf(2)).equal(uintOf(1))).isSameAs(True); + assertThat(uintOf(-1L).divide(uintOf(2)).equal(uintOf(Long.MAX_VALUE))).isSameAs(True); + assertThat(uintOf(-1L).divide(uintOf(Long.MIN_VALUE)).equal(uintOf(1))).isSameAs(True); + assertThat(uintOf(Long.MIN_VALUE).divide(uintOf(2)).equal(uintOf(1L << 62))).isSameAs(True); assertThat(UintZero.divide(UintZero)) .isInstanceOf(Err.class) .extracting(Object::toString) @@ -196,6 +199,10 @@ void uintEqual() { @Test void uintModulo() { assertThat(uintOf(21).modulo(uintOf(2)).equal(uintOf(1))).isSameAs(True); + assertThat(uintOf(-1L).modulo(uintOf(2)).equal(uintOf(1))).isSameAs(True); + assertThat(uintOf(-1L).modulo(uintOf(Long.MIN_VALUE)).equal(uintOf(Long.MAX_VALUE))) + .isSameAs(True); + assertThat(uintOf(Long.MIN_VALUE).modulo(uintOf(3)).equal(uintOf(2))).isSameAs(True); assertThat(uintOf(21).modulo(UintZero)) .isInstanceOf(Err.class) .extracting(Object::toString)