swiftlang / swift-corelibs-foundation

The Foundation Project, providing core utilities, internationalization, and OS independence
swift.org
Apache License 2.0
5.29k stars 1.13k forks source link

[SR-7119] Swift.Decodable doesn't work properly with big Int64 numbers on iOS 10 #4250

Open swift-ci opened 6 years ago

swift-ci commented 6 years ago
Previous ID SR-7119
Radar None
Original Reporter vincent (JIRA User)
Type Bug
Environment iOS 10 Swift 4.0
Additional Detail from JIRA | | | |------------------|-----------------| |Votes | 2 | |Component/s | Foundation | |Labels | Bug, Codable | |Assignee | None | |Priority | Medium | md5: 7519541942cc0ceab4b15571af866560

Issue Description:

The "Parsed JSON number <1000000000000000070> does not fit in Int64." error occurs when running the following code on iOS 10.

struct MyDecodable: Decodable {
    var id: Int64
}

let str = "{\"id\":1000000000000000070}"
let data = str.data(using: .utf8)!
let decodable = try! JSONDecoder().decode(MyDecodable.self, from: data)

It seems that on iOS 10, for some big numbers that fit in an Int64, JSONSerialization creates not a normal NSNumber but an instance of NSDecimalNumber.
On iOS 11, a big number like the one above becomes an NSNumber so everything works fine.

iOS 10 probably can't be fixed but it seems to me that changing the code at https://github.com/apple/swift/blob/a62647f0685c3c832756d9f635cfe527d45037de/stdlib/public/SDK/Foundation/JSONEncoder.swift#L2100-L2103 to the code below would fix the problem.

let int64 = number.int64Value
let recreatedNumber = number is NSDecimalNumber ? NSDecimalNumber(value: int64) : NSNumber(value: int64)
guard recreatedNumber == number else {
    throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Parsed JSON number <\(number)> does not fit in \(type)."))
}
swift-ci commented 6 years ago

Comment by Fil Sviatoslav (JIRA)

Someone, when it's, will be fixed? (@belkadan?)

swift-ci commented 5 years ago

Comment by Junkai Wu (JIRA)

Still not fixed...