Open adamtow opened 2 years ago
Interesting. Which beta is it? And may I ask:
This has been happening since Beta 1 of Xcode 14, and we're on Beta 4. I extracted the contents of the slice where it crashed, but when I put it into a non-network code sample, the array slice was processed correctly (see below):
// This array slice for the AEBP message did not cause a crash
let testArrayWorks: [UInt8] = [0x00, 0x01, 0x74, 0x62, 0x6F, 0x61, 0x72, 0x64, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x33, 0x10, 0x01, 0x01, 0x65, 0x64, 0x00, 0x00, 0x00, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x03, 0x43]
debugPrint("testWorks")
let msg = try Message.Did.ChangeFairlightMixerSourceEqualizerBand(with: testArrayWorks[0..<testArrayWorks.count])
debugPrint(msg.debugDescription)
// This array slice for the AEBP message caused a crash on a real device
let testArrayCrash: [UInt8] = [0x00, 0x01, 0x00, 0x08, 0x01, 0x54, 0xB2, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x01, 0x01, 0x2D, 0x01, 0x0F, 0x01, 0x00, 0x20, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x70, 0x68]
debugPrint("testCrash")
let msg2 = try Message.Did.ChangeFairlightMixerSourceEqualizerBand(with: testArrayCrash[0..<testArrayCrash.count])
debugPrint(msg2.debugDescription)
The error that I'm seeing is NIO-ELT-0-#0 (2): Fatal error
It's occurring when trying to process the Int64 value for the sourceId. This is running off of an ATEM Mini Extreme ISO or ATEM Mini Pro.
Stack trace:
#0 0x00000001a56b932c in _swift_runtime_on_report ()
#1 0x00000001a574e8d8 in _swift_stdlib_reportFatalErrorInFile ()
#2 0x00000001a53721b0 in closure #1 in closure #1 in closure #1 in _assertionFailure(_:_:file:line:flags:) ()
#3 0x00000001a5371ef4 in closure #1 in closure #1 in _assertionFailure(_:_:file:line:flags:) ()
#4 0x00000001a5371cec in closure #1 in _assertionFailure(_:_:file:line:flags:) ()
#5 0x00000001a537184c in _assertionFailure(_:_:file:line:flags:) ()
#6 0x00000001a5371b90 in _fatalErrorMessage(_:_:file:line:flags:) ()
#7 0x00000001004804a8 in _swift_se0333_UnsafePointer_withMemoryRebound ()
#8 0x000000010048014c in closure #1 in FixedWidthInteger.init(from:) at /Users/adam/Development/swift-atem-plus/Sources/Atem/Utilities/IntOperators.swift:18
#9 0x000000010048019c in partial apply for closure #1 in FixedWidthInteger.init(from:) ()
#10 0x00000001a53688cc in ArraySlice.withUnsafeBufferPointer<τ_0_0>(_:) ()
#11 0x000000010047ff80 in FixedWidthInteger.init(from:) at /Users/adam/Development/swift-atem-plus/Sources/Atem/Utilities/IntOperators.swift:17
#12 0x00000001002a2650 in Message.Did.ChangeFairlightMixerSourceEqualizerBand.init(with:) at /Users/adam/Development/swift-atem-plus/Sources/Atem/Messages/FairlightAudio+Dynamics.swift:1627
#13 0x00000001002a3a5c in protocol witness for DeserializableMessage.init(with:) in conformance Message.Did.ChangeFairlightMixerSourceEqualizerBand ()
#14 0x00000001001edeec in MessageParser.message(from:) at /Users/adam/Development/swift-atem-plus/Sources/Atem/MessageHandler.swift:91
#15 0x00000001001eea2c in PureMessageHandler.handle(rawMessage:) at /Users/adam/Development/swift-atem-plus/Sources/Atem/MessageHandler.swift:54
#16 0x00000001001eec10 in PureMessageHandler.handle(messages:) at /Users/adam/Development/swift-atem-plus/Sources/Atem/MessageHandler.swift:62
#17 0x00000001001dce24 in ControllerHandler.channelRead(context:data:) at /Users/adam/Development/swift-atem-plus/Sources/Atem/Controller.swift:36
#18 0x0000000100467680 in protocol witness for _ChannelInboundHandler.channelRead(context:data:) in conformance HandlerWithTimer ()
#19 0x00000001000a5a38 in ChannelHandlerContext.invokeChannelRead(_:) at /Users/adam/Library/Developer/Xcode/DerivedData/swift-atem-plus-clgyggiojrmkrdfiftaqreynemgz/SourcePackages/checkouts/swift-nio/Sources/NIOCore/ChannelPipeline.swift:1688
#20 0x00000001000a2450 in ChannelPipeline.fireChannelRead0(_:) at /Users/adam/Library/Developer/Xcode/DerivedData/swift-atem-plus-clgyggiojrmkrdfiftaqreynemgz/SourcePackages/checkouts/swift-nio/Sources/NIOCore/ChannelPipeline.swift:897
#21 0x00000001000a7f38 in ChannelPipeline.SynchronousOperations.fireChannelRead(_:) at /Users/adam/Library/Developer/Xcode/DerivedData/swift-atem-plus-clgyggiojrmkrdfiftaqreynemgz/SourcePackages/checkouts/swift-nio/Sources/NIOCore/ChannelPipeline.swift:1158
#22 0x00000001001c47a0 in DatagramChannel.singleReadFromSocket() at /Users/adam/Library/Developer/Xcode/DerivedData/swift-atem-plus-clgyggiojrmkrdfiftaqreynemgz/SourcePackages/checkouts/swift-nio/Sources/NIOPosix/SocketChannel.swift:593
#23 0x00000001001c38d4 in DatagramChannel.readFromSocket() at /Users/adam/Library/Developer/Xcode/DerivedData/swift-atem-plus-clgyggiojrmkrdfiftaqreynemgz/SourcePackages/checkouts/swift-nio/Sources/NIOPosix/SocketChannel.swift:542
#24 0x0000000100144580 in BaseSocketChannel.readable0() at /Users/adam/Library/Developer/Xcode/DerivedData/swift-atem-plus-clgyggiojrmkrdfiftaqreynemgz/SourcePackages/checkouts/swift-nio/Sources/NIOPosix/BaseSocketChannel.swift:1061
#25 0x000000010014571c in BaseSocketChannel.readable() at /Users/adam/Library/Developer/Xcode/DerivedData/swift-atem-plus-clgyggiojrmkrdfiftaqreynemgz/SourcePackages/checkouts/swift-nio/Sources/NIOPosix/BaseSocketChannel.swift:1045
#26 0x000000010014665c in protocol witness for SelectableChannel.readable() in conformance BaseSocketChannel<τ_0_0> ()
#27 0x00000001001a2708 in SelectableEventLoop.handleEvent<τ_0_0>(_:channel:) at /Users/adam/Library/Developer/Xcode/DerivedData/swift-atem-plus-clgyggiojrmkrdfiftaqreynemgz/SourcePackages/checkouts/swift-nio/Sources/NIOPosix/SelectableEventLoop.swift:394
#28 0x00000001001a3bac in closure #2 in closure #2 in SelectableEventLoop.run() at /Users/adam/Library/Developer/Xcode/DerivedData/swift-atem-plus-clgyggiojrmkrdfiftaqreynemgz/SourcePackages/checkouts/swift-nio/Sources/NIOPosix/SelectableEventLoop.swift:471
#29 0x00000001001a7de8 in partial apply for closure #2 in closure #2 in SelectableEventLoop.run() ()
#30 0x00000001001b5aa4 in Selector.whenReady0(strategy:onLoopBegin:_:) at /Users/adam/Library/Developer/Xcode/DerivedData/swift-atem-plus-clgyggiojrmkrdfiftaqreynemgz/SourcePackages/checkouts/swift-nio/Sources/NIOPosix/SelectorKqueue.swift:258
#31 0x00000001001ae7d4 in Selector.whenReady(strategy:onLoopBegin:_:) at /Users/adam/Library/Developer/Xcode/DerivedData/swift-atem-plus-clgyggiojrmkrdfiftaqreynemgz/SourcePackages/checkouts/swift-nio/Sources/NIOPosix/SelectorGeneric.swift:286
#32 0x00000001001a3874 in closure #2 in SelectableEventLoop.run() at /Users/adam/Library/Developer/Xcode/DerivedData/swift-atem-plus-clgyggiojrmkrdfiftaqreynemgz/SourcePackages/checkouts/swift-nio/Sources/NIOPosix/SelectableEventLoop.swift:461
#33 0x00000001001a6cd0 in partial apply for closure #2 in SelectableEventLoop.run() ()
#34 0x000000010019ea40 in closure #1 in withAutoReleasePool<τ_0_0>(_:) at /Users/adam/Library/Developer/Xcode/DerivedData/swift-atem-plus-clgyggiojrmkrdfiftaqreynemgz/SourcePackages/checkouts/swift-nio/Sources/NIOPosix/SelectableEventLoop.swift:25
#35 0x000000010019eaa4 in partial apply for closure #1 in withAutoReleasePool<τ_0_0>(_:) ()
#36 0x00000001acddead4 in autoreleasepool<τ_0_0>(invoking:) ()
#37 0x000000010019e9d4 in withAutoReleasePool<τ_0_0>(_:) at /Users/adam/Library/Developer/Xcode/DerivedData/swift-atem-plus-clgyggiojrmkrdfiftaqreynemgz/SourcePackages/checkouts/swift-nio/Sources/NIOPosix/SelectableEventLoop.swift:24
#38 0x00000001001a2ab8 in SelectableEventLoop.run() at /Users/adam/Library/Developer/Xcode/DerivedData/swift-atem-plus-clgyggiojrmkrdfiftaqreynemgz/SourcePackages/checkouts/swift-nio/Sources/NIOPosix/SelectableEventLoop.swift:460
#39 0x0000000100174b74 in static MultiThreadedEventLoopGroup.runTheLoop(thread:parentGroup:canEventLoopBeShutdownIndividually:selectorFactory:initializer:_:) at /Users/adam/Library/Developer/Xcode/DerivedData/swift-atem-plus-clgyggiojrmkrdfiftaqreynemgz/SourcePackages/checkouts/swift-nio/Sources/NIOPosix/MultiThreadedEventLoopGroup.swift:89
#40 0x0000000100175100 in closure #1 in static MultiThreadedEventLoopGroup.setupThreadAndEventLoop(name:parentGroup:selectorFactory:initializer:) at /Users/adam/Library/Developer/Xcode/DerivedData/swift-atem-plus-clgyggiojrmkrdfiftaqreynemgz/SourcePackages/checkouts/swift-nio/Sources/NIOPosix/MultiThreadedEventLoopGroup.swift:110
#41 0x000000010017a70c in partial apply for closure #1 in static MultiThreadedEventLoopGroup.setupThreadAndEventLoop(name:parentGroup:selectorFactory:initializer:) ()
#42 0x00000001001d16b4 in thunk for @escaping @callee_guaranteed (@guaranteed NIOThread) -> () ()
#43 0x00000001001d575c in closure #1 in static ThreadOpsPosix.run(handle:args:detachThread:) at /Users/adam/Library/Developer/Xcode/DerivedData/swift-atem-plus-clgyggiojrmkrdfiftaqreynemgz/SourcePackages/checkouts/swift-nio/Sources/NIOPosix/ThreadPosix.swift:105
#44 0x00000001001d5818 in @objc closure #1 in static ThreadOpsPosix.run(handle:args:detachThread:) ()
#45 0x00000001011c1890 in _pthread_start ()
FWIW, I found this code which is another take on your `init(from slice: ArraySlice
extension FixedWidthInteger {
init<I>(from iterator: inout I)
where I: IteratorProtocol, I.Element == UInt8 {
self = stride(from: 0, to: Self.bitWidth, by: 8).reduce(into: 0) {
$0 |= Self(truncatingIfNeeded: iterator.next()!) &<< $1
}
}
init<C>(from bytes: C) where C: Collection, C.Element == UInt8 {
// precondition(bytes.count == (Self.bitWidth+7)/8)
// let bitWidth = (Self.bitWidth+7)/8
// debugPrint("Bytes Count: \(bytes.count) Bitwidth: \(bitWidth)")
// assert(bytes.count == (Self.bitWidth+7)/8)
var iter = bytes.reversed().makeIterator()
self.init(from: &iter)
}
init(from slice: ArraySlice<UInt8>) {
if #available(iOS 16, OSX 12, *) {
self.init(from: Array(slice))
} else {
self.init(bigEndian: slice.withUnsafeBufferPointer {
$0.baseAddress!.withMemoryRebound(to: Self.self, capacity: 1) {$0.pointee}
})
}
}
var bytes: [UInt8] {
let byteCount = bitWidth >> 3
return [UInt8](unsafeUninitializedCapacity: byteCount) { (pointer, count) in
UnsafeMutableRawPointer(pointer.baseAddress!).bindMemory(to: Self.self, capacity: 1).pointee = bigEndian
count = byteCount
}
}
}
You can run the Simulator target in swift-atem and the sample code above to replicate the error too. The fatal error may occur on a different message like _VMC
.
0x10048036c <+324>: bl 0x100480428 ; _swift_se0333_UnsafePointer_withMemoryRebound at <compiler-generated>
**-> 0x100480370 <+328>: stur x21, [x29, #-0x78]**
0x100480374 <+332>: cbnz x21, 0x100480398 ; <+368> at IntOperators.swift:40:21
0x100480378 <+336>: b 0x10048037c ; <+340> at IntOperators.swift
NIO-ELT-0-#0 (2): Fatal error
Command: Optional("_VMC")
"Getting array slice: [95, 77, 65, 67]"
Swift/arm64e-apple-macos.swiftinterface:23320: Fatal error
2022-07-29 09:45:13.856773-0700 Audio[40176:3315934] Swift/arm64e-apple-macos.swiftinterface:23320: Fatal error
Well actually I can't run your code because it has references to a lot of other types that I don't have... But where does FairlightAudio+Dynamics.swift:1627 point to in your Message.Did.ChangeFairlightMixerSourceEqualizerBand.init(with:)
intialiser code?
This should help you out:
public struct FairlightEqualizerBandShape: OptionSet {
public let rawValue: UInt8
public init(rawValue: UInt8) {
self.rawValue = rawValue
}
public static let lowShelf = Self(rawValue: 1 << 0)
public static let lowPass = Self(rawValue: 1 << 1)
public static let bandPass = Self(rawValue: 1 << 2)
public static let notch = Self(rawValue: 1 << 3)
public static let highPass = Self(rawValue: 1 << 4)
public static let highShelf = Self(rawValue: 1 << 5)
public static let options: [FairlightEqualizerBandShape] =
[
.lowShelf,
.lowPass,
.bandPass,
.notch,
.highPass,
.highShelf
]
}
public struct FairlightEqualizerFrequencyRange: OptionSet {
public let rawValue: UInt8
public init(rawValue: UInt8) {
self.rawValue = rawValue
}
public static let low = Self(rawValue: 1 << 0)
public static let midLow = Self(rawValue: 1 << 1)
public static let midHigh = Self(rawValue: 1 << 2)
public static let high = Self(rawValue: 1 << 3)
public static let options: [FairlightEqualizerFrequencyRange] =
[
.low,
.midLow,
.midHigh,
.high
]
}
extension Message.Did {
/// Informs a controller that a source's equalizer settings have changed
public struct ChangeFairlightMixerSourceEqualizerBand: SerializableMessage {
public static let title = Message.Title(string: "AEBP")
public let index: AudioSource
public let sourceId: Int64
public let band: UInt8
public let bandEnabled: Bool
public let supportedShapes: FairlightEqualizerBandShape
public let shape: FairlightEqualizerBandShape
public let supportedFrequencyRanges: FairlightEqualizerFrequencyRange
public let frequencyRange: FairlightEqualizerFrequencyRange
public let frequency: UInt32
public let gain: Int32
public let qFactor: Int16
public init(with bytes: ArraySlice<UInt8>) throws {
debugPrint(bytes)
self.index = AudioSource(rawValue: UInt16(from: bytes[relative: Position.index]))
self.sourceId = Int64(from: bytes[relative: Position.sourceId])
self.band = bytes[relative: Position.band]
self.bandEnabled = bytes[relative: Position.bandEnabled].firstBit
self.supportedShapes = FairlightEqualizerBandShape(rawValue: bytes[relative: Position.supportedShapes])
self.shape = FairlightEqualizerBandShape(rawValue: bytes[relative: Position.shape])
self.supportedFrequencyRanges = FairlightEqualizerFrequencyRange(rawValue: bytes[relative: Position.supportedFrequencyRanges])
self.frequencyRange = FairlightEqualizerFrequencyRange(rawValue: bytes[relative: Position.frequencyRange])
self.frequency = UInt32(from: bytes[relative: Position.frequency])
self.gain = Int32(from: bytes[relative: Position.gain])
self.qFactor = Int16(from: bytes[relative: Position.qFactor])
}
public init(index: AudioSource, sourceId: Int64, band: UInt8, bandEnabled: Bool, supportedShapes: FairlightEqualizerBandShape, shape: FairlightEqualizerBandShape, supportedFrequencyRanges: FairlightEqualizerFrequencyRange, frequencyRange: FairlightEqualizerFrequencyRange, frequency: UInt32, gain: Int32, qFactor: Int16) {
self.index = index
self.sourceId = sourceId
self.band = band
self.bandEnabled = bandEnabled
self.supportedShapes = supportedShapes
self.shape = shape
self.supportedFrequencyRanges = supportedFrequencyRanges
self.frequencyRange = frequencyRange
self.frequency = frequency
self.gain = gain
self.qFactor = qFactor
}
public var dataBytes: [UInt8] {
.init(unsafeUninitializedCapacity: 36) { (buffer, count) in
buffer.write(index.rawValue.bigEndian, at: Position.index.lowerBound)
buffer.write(sourceId.bigEndian, at: Position.sourceId.lowerBound)
buffer[Position.band] = band
buffer[Position.bandEnabled] = bandEnabled ? 1 : 0
buffer[Position.supportedShapes] = supportedShapes.rawValue
buffer[Position.shape] = shape.rawValue
buffer[Position.supportedFrequencyRanges] = supportedFrequencyRanges.rawValue
buffer[Position.frequencyRange] = frequencyRange.rawValue
buffer.write(frequency.bigEndian, at: Position.frequency.lowerBound)
buffer.write(gain.bigEndian, at: Position.gain.lowerBound)
buffer.write(qFactor.bigEndian, at: Position.qFactor.lowerBound)
count = 36
}
}
public var debugDescription: String { return """
Did.ChangeFairlightMixerSourceEqualizerBand {
index: \(index),
sourceId: \(sourceId),
band: \(band),
bandEnabled: \(bandEnabled),
supportedShapes: \(supportedShapes),
shape: \(shape),
supportedFrequencyRanges: \(supportedFrequencyRanges),
frequencyRange: \(frequencyRange),
frequency: \(frequency),
gain: \(gain),
qFactor: \(qFactor),
}
"""
}
enum Position {
static let index = 0..<2
static let sourceId = 8..<16
static let band = 16
static let bandEnabled = 17
static let supportedShapes = 18
static let shape = 19
static let supportedFrequencyRanges = 20
static let frequencyRange = 21
static let frequency = 24..<28
static let gain = 28..<32
static let qFactor = 32..<34
}
}
}
@Dev1an Were you able to reproduce this on your end?
There are some comments about changes to unaligned access to data in buffer pointers that might be relevant?
https://developer.apple.com/documentation/Xcode-Release-Notes/xcode-14-release-notes?changes=_2
Here's another possible workaround that does not result in crashes in my limited testing. From this link:
https://stackoverflow.com/questions/52080844/fatal-error-when-using-withmemoryrebound-in-ios-swift
init(from slice: ArraySlice<UInt8>) {
self.init(bigEndian: slice.withUnsafeBufferPointer {
let uint = UnsafeRawBufferPointer($0).bindMemory(to: Self.self)
return uint.baseAddress!.pointee
})
}
@Dev1an, I am facing the same issue. Any plan to fix it in the upcoming release? @adamtow. the solution works for me but every time I need to change that init method when package reload.
Note:- I am using Xcode 14.2
@iosmoon38 you can create a fork of this repo and just include the fix above. Then, the code won't get replaced everything you update the package.
@adamtow, Thanks for giving me solution. fork is worked for me.
@Dev1an, is there any chance to fix this issue in the upcoming release?
Running the Xcode 14 beta, I'm seeing fatal errors when initializing variables from messages sent from the ATEM. Seems like the code here is triggering the error:
Building the same code using Xcode 13.4.1 does not result in an error when running.
This particular message causes an error to happen is
AEBP
which returns information when a Fairlight Audio Mixer Source Equalizer Band has changed:and the code to call it out: