Hello everyone, I have the following code to decode a Date from wire data, it works fine on macOS but it crashes code on linux (specifically ubuntu 22). The crash occurs when I am constructing a Date
from DateComponents
via Calendar.date(from:)
. The crash is a Code 4 SIGTRAP
. Am I doing anything wrong?
I've added example code to reproduce the crash below:
import struct Foundation.Calendar
import struct Foundation.Date
import struct Foundation.DateComponents
import struct Foundation.TimeZone
import NIOCore
enum Constants {
static let TNS_HAS_REGION_ID: UInt8 = 0x80
static let TZ_HOUR_OFFSET: UInt8 = 20
static let TZ_MINUTE_OFFSET: UInt8 = 60
}
public extension Date {
init(
from buffer: inout ByteBuffer
) throws {
let length = buffer.readableBytes
guard
length >= 7,
let firstSevenBytes = buffer.readBytes(length: 7)
else {
// throw OracleDecodingError.Code.missingData
fatalError()
}
let year = (Int(firstSevenBytes[0]) - 100) * 100 +
Int(firstSevenBytes[1]) - 100
let month = Int(firstSevenBytes[2])
let day = Int(firstSevenBytes[3])
let hour = Int(firstSevenBytes[4]) - 1
let minute = Int(firstSevenBytes[5]) - 1
let second = Int(firstSevenBytes[6]) - 1
var calendar = Calendar(identifier: .gregorian)
calendar.timeZone = TimeZone(secondsFromGMT: 0)!
var components = DateComponents(
calendar: calendar,
year: year,
month: month,
day: day,
hour: hour,
minute: minute,
second: second
)
if length >= 11, let value = buffer.readInteger(
endianness: .big, as: UInt32.self
) {
let fsecond = Double(value) / 1000.0
components.nanosecond = Int(fsecond * 1_000_000_000)
}
let (byte11, byte12) = buffer
.readMultipleIntegers(as: (UInt8, UInt8).self) ?? (0, 0)
if length > 11, byte11 != 0, byte12 != 0 {
if byte11 & Constants.TNS_HAS_REGION_ID != 0 {
// Named time zones are not supported
// throw OracleDecodingError.Code.failure
fatalError()
}
let tzHour = Int(byte11 - Constants.TZ_HOUR_OFFSET)
let tzMinute = Int(byte12 - Constants.TZ_MINUTE_OFFSET)
if tzHour != 0 || tzMinute != 0 {
guard let timeZone = TimeZone(
secondsFromGMT: tzHour * 3600 + tzMinute * 60
) else {
// throw OracleDecodingError.Code.failure
fatalError()
}
components.timeZone = timeZone
}
}
guard let value = calendar.date(from: components) else {
// . ^ crash happens here
// throw OracleDecodingError.Code.failure
fatalError()
}
self = value
}
}
Example:
var buffer = ByteBuffer(bytes: [120, 123, 8, 27, 20, 31, 49, 36, 58, 250, 136, 20, 60])
print(try? Date(from: &buffer))
Call Stack:
function signature specialization <Arg[4] = Dead> of Foundation.NSCalendar._convert(_: Swift.Optional<Swift.Int>, type: Swift.String, vector: inout Swift.Array<Swift.Int32>, compDesc: inout Swift.Array<Swift.Int8>) -> () (@function signature specialization <Arg[4] = Dead> of Foundation.NSCalendar._convert(_: Swift.Optional<Swift.Int>, type: Swift.String, vector: inout Swift.Array<Swift.Int32>, compDesc: inout Swift.Array<Swift.Int8>) -> ():22)
function signature specialization <Arg[1] = Dead> of Foundation.NSCalendar._convert(Foundation.DateComponents) -> (Swift.Array<Swift.Int32>, Swift.Array<Swift.Int8>) (@function signature specialization <Arg[1] = Dead> of Foundation.NSCalendar._convert(Foundation.DateComponents) -> (Swift.Array<Swift.Int32>, Swift.Array<Swift.Int8>):171)
Foundation.NSCalendar.date(from: Foundation.DateComponents) -> Swift.Optional<Foundation.Date> (@Foundation.NSCalendar.date(from: Foundation.DateComponents) -> Swift.Optional<Foundation.Date>:13)
partial apply forwarder for closure #1 (Foundation.NSCalendar) -> Swift.Optional<Foundation.Date> in Foundation.Calendar.date(from: Foundation.DateComponents) -> Swift.Optional<Foundation.Date> (@partial apply forwarder for closure #1 (Foundation.NSCalendar) -> Swift.Optional<Foundation.Date> in Foundation.Calendar.date(from: Foundation.DateComponents) -> Swift.Optional<Foundation.Date>:15)
Foundation._MutableHandle.map<τ_0_0>((τ_0_0) throws -> τ_1_0) throws -> τ_1_0 (@Foundation._MutableHandle.map<τ_0_0>((τ_0_0) throws -> τ_1_0) throws -> τ_1_0:25)
Foundation.Calendar.date(from: Foundation.DateComponents) -> Swift.Optional<Foundation.Date> (@Foundation.Calendar.date(from: Foundation.DateComponents) -> Swift.Optional<Foundation.Date>:20)
Foundation.Date.init(from: inout NIOCore.ByteBuffer) throws -> Foundation.Date (/workspaces/test1/DateDecoding.swift:70)