From 8373c8d8fbf2b1e3ea3af8f374ee41f348bb3dc2 Mon Sep 17 00:00:00 2001 From: Charles Hu Date: Wed, 14 Aug 2024 13:48:34 -0700 Subject: [PATCH] [6.0] Resolved an arithmetic overflow error in Decimal division caused by improper upcasting (#850) - Upcast numbers to higher bitwidth before performing calculations. resolves: rdar://133458109 resolves: https://github.com/apple/swift-foundation/issues/595 --- .../Decimal/Decimal+Math.swift | 2 +- .../DecimalTests.swift | 27 ++++++++++++++++++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/Sources/FoundationEssentials/Decimal/Decimal+Math.swift b/Sources/FoundationEssentials/Decimal/Decimal+Math.swift index 172454463..cdda50dc9 100644 --- a/Sources/FoundationEssentials/Decimal/Decimal+Math.swift +++ b/Sources/FoundationEssentials/Decimal/Decimal+Math.swift @@ -945,7 +945,7 @@ extension Decimal { // D1: Normalize // Calculate d such that `d*highest_dight_of_divisor >= b/2 (0x8000) - let d = (1 << 16) / UInt32(divisor[divisor.count - 1] + 1) + let d: UInt32 = (1 << 16) / (UInt32(divisor[divisor.count - 1]) + 1) // This is to make the whole algorithm work and // (dividend * d) / (divisor * d) == dividend / divisor var normalizedDividend = try self._integerMultiplyByShort( diff --git a/Tests/FoundationEssentialsTests/DecimalTests.swift b/Tests/FoundationEssentialsTests/DecimalTests.swift index b6c958f7d..9a1db4d56 100644 --- a/Tests/FoundationEssentialsTests/DecimalTests.swift +++ b/Tests/FoundationEssentialsTests/DecimalTests.swift @@ -613,6 +613,32 @@ final class DecimalTests : XCTestCase { XCTAssertTrue(Decimal._compare(lhs: expected, rhs: result) == .orderedSame) } + func testCrashingDivision() throws { + // This test makes sure the following division + // does not crash + let first: Decimal = Decimal(1147858867) + let second: Decimal = Decimal(4294967295) + let result = first / second + let expected: Decimal = Decimal( + _exponent: -38, + _length: 8, + _isNegative: 0, + _isCompact: 1, + _reserved: 0, + _mantissa: ( + 58076, + 13229, + 12316, + 25502, + 15252, + 32996, + 11611, + 5147 + ) + ) + XCTAssertEqual(result, expected) + } + func testPower() throws { var a = Decimal(1234) var result = try a._power(exponent: 0, roundingMode: .plain) @@ -1272,5 +1298,4 @@ final class DecimalTests : XCTestCase { XCTAssertEqual(length, 3) } #endif - }