From c0a4d37011367e09f572bda8e9ffe3be26fb1014 Mon Sep 17 00:00:00 2001 From: Fabio Niephaus Date: Tue, 12 Feb 2019 14:01:36 +0100 Subject: [PATCH 1/2] Fix overflow bug in DividePrim `Long.MIN_VALUE / -1` is the only division that overflows. Since the result is well-known, it can be precomputed. "In cases where the size is int or long and overflow errors need to be detected, the methods addExact, subtractExact, multiplyExact, and toIntExact throw an ArithmeticException when the results overflow. For other arithmetic operations such as divide, absolute value, increment, decrement, and negation overflow occurs only with a specific minimum or maximum value and should be checked against the minimum or maximum as appropriate." See https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html Signed-off-by: Stefan Marr --- src/som/primitives/arithmetic/DividePrim.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/som/primitives/arithmetic/DividePrim.java b/src/som/primitives/arithmetic/DividePrim.java index 6793d0b2c..5a6d8a309 100644 --- a/src/som/primitives/arithmetic/DividePrim.java +++ b/src/som/primitives/arithmetic/DividePrim.java @@ -12,11 +12,19 @@ @GenerateNodeFactory @Primitive(primitive = "int:divideBy:", selector = "/") public abstract class DividePrim extends ArithmeticPrim { - @Specialization + private static final BigInteger OVERFLOW_RESULT = + BigInteger.valueOf(Long.MIN_VALUE).divide(BigInteger.valueOf(-1)); + + @Specialization(guards = "!isOverflowDivision(left, right)") public final long doLong(final long left, final long right) { return left / right; } + @Specialization(guards = "isOverflowDivision(left, right)") + public final Object doLongWithOverflow(final long left, final long right) { + return OVERFLOW_RESULT; + } + @Specialization @TruffleBoundary public final Object doBigInteger(final BigInteger left, final BigInteger right) { @@ -40,4 +48,8 @@ public final Object doLong(final long left, final BigInteger right) { public final Object doLong(final long left, final double right) { return (long) (left / right); } + + protected static final boolean isOverflowDivision(final long left, final long right) { + return left == Long.MIN_VALUE && right == -1; + } } From cea6675de2dd56b553c4c2bf0d7869556cede9d7 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Mon, 5 Aug 2019 17:55:39 +0100 Subject: [PATCH 2/2] Added test to trigger division overflow Signed-off-by: Stefan Marr --- core-lib/TestSuite/IntegerTests.ns | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core-lib/TestSuite/IntegerTests.ns b/core-lib/TestSuite/IntegerTests.ns index 5f6aac59f..a0fd57504 100644 --- a/core-lib/TestSuite/IntegerTests.ns +++ b/core-lib/TestSuite/IntegerTests.ns @@ -195,6 +195,11 @@ class IntegerTests usingPlatform: platform testFramework: minitest = ( self assert: 3 equals: 7 / 2.0. self assert: 2 equals: 7 / 3.5. + + self assert: 9223372036854775808 equals: (* Java.MIN_VALUE *) -9223372036854775808 / -1. + + (* To trigger issue, we need to compute the value, because it is otherwise parsed as a big integer *) + self assert: 9223372036854775808 equals: (* Java.MIN_VALUE *) ((-922337203685477580 * 10) - 8) / -1. ) public testDouble = (