Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IdentifiedArray Subscript Read crash #26

Closed
Antonito opened this issue Oct 10, 2021 · 2 comments · Fixed by #32
Closed

IdentifiedArray Subscript Read crash #26

Antonito opened this issue Oct 10, 2021 · 2 comments · Fixed by #32
Labels
apple bug Something isn't working due to a bug on Apple's platforms.

Comments

@Antonito
Copy link

Hello,

I'm migrating an app to TCA and experiencing crashes in IdentifiedArray.subscript.read during an equality check.
Unfortunately I haven't been able to reproduce this case in an isolated example yet.

I haven't been able to reproduce the crash in a predictable way with my app either (it seems to appear 'randomly') – but it seems to be triggered by the use Reducer.debug.

Here is my stack trace:

#0	0x0000000188588cf4 in _swift_runtime_on_report ()
#1	0x0000000188608e60 in _swift_stdlib_reportFatalErrorInFile ()
#2	0x000000018823e23c in closure #1 in closure #1 in closure #1 in _assertionFailure(_:_:file:line:flags:) ()
#3	0x000000018823dfdc in closure #1 in closure #1 in _assertionFailure(_:_:file:line:flags:) ()
#4	0x000000018823d8d0 in _assertionFailure(_:_:file:line:flags:) ()
#5	0x000000018828a0b4 in ContiguousArray.subscript.getter ()
#6	0x0000000104a75860 in OrderedDictionary.Elements.subscript.getter at [...]/checkouts/swift-collections/Sources/OrderedCollections/OrderedDictionary/OrderedDictionary+Elements.swift:273
#7	0x0000000104a54260 in IdentifiedArray.subscript.read at [...]/checkouts/swift-identified-collections/Sources/IdentifiedCollections/IdentifiedArray/IdentifiedArray+Collection.swift:17
#8	0x0000000104a54a04 in protocol witness for Collection.subscript.read in conformance IdentifiedArray<τ_0_0, τ_0_1> ()
#9	0x000000018827c408 in protocol witness for IteratorProtocol.next() in conformance IndexingIterator<τ_0_0> ()
#10	0x00000001883b53a8 in Sequence<>.elementsEqual<τ_0_0>(_:) ()
#11	0x0000000105945b38 in static FriendManagerState.== infix(_:_:) at [...]/Sources/FriendProfileState/FriendManagerState.swift:36
#12	0x0000000105945dd8 in protocol witness for static Equatable.== infix(_:_:) in conformance FriendManagerState ()
#13	0x00000001882a1748 in static Optional<τ_0_0>.== infix(_:_:) ()
#14	0x0000000104a4f6bc in static Box<τ_0_0>.isEqual(_:_:) at [...]/checkouts/swift-custom-dump/Sources/CustomDump/Internal/Box.swift:11
#15	0x0000000104a4f764 in protocol witness for static AnyEquatable.isEqual(_:_:) in conformance <τ_0_0> Box<τ_0_0> ()
#16	0x0000000104a4fe24 in open #1 <τ_0_0>(_:) in isMirrorEqual(_:_:) at [...]/checkouts/swift-custom-dump/Sources/CustomDump/Internal/Box.swift:17
#17	0x0000000104a4f8c4 in isMirrorEqual(_:_:) at [...]/checkouts/swift-custom-dump/Sources/CustomDump/Internal/Box.swift:19
#18	0x0000000104a3e8bc in diff<τ_0_0>(_:_:format:) at [...]/checkouts/swift-custom-dump/Sources/CustomDump/Diff.swift:518
#19	0x00000001049219ac in closure #1 in closure #1 in closure #1 in Reducer.debug<τ_0_0, τ_0_1>(_:state:action:actionFormat:environment:) at [...]/checkouts/swift-composable-architecture/Sources/ComposableArchitecture/Debugging/ReducerDebugging.swift:127
#20	0x00000001049235d4 in partial apply for closure #1 in closure #1 in closure #1 in Reducer.debug<τ_0_0, τ_0_1>(_:state:action:actionFormat:environment:) ()
#21	0x0000000104922068 in thunk for @escaping @callee_guaranteed () -> () ()
#22	0x0000000109b40a20 in _dispatch_call_block_and_release ()
#23	0x0000000109b42700 in _dispatch_client_callout ()
#24	0x0000000109b4a83c in _dispatch_lane_serial_drain ()
#25	0x0000000109b4b558 in _dispatch_lane_invoke ()
#26	0x0000000109b57fa0 in _dispatch_workloop_worker_thread ()
#27	0x00000001f33a91b0 in _pthread_wqthread ()

From what I've been able to debug, at some point IdentifiedArray.subscript(position:Int) is called with an invalid position.
The _keys and _values elements of _dictionary go out of sync (in my case, _keys contains 14 elements whereas _dictionary only contains 13 – which causes an out of range access).

For performances reason, one of my TCA state is a class, not a struct, and the crash occurs when its equality is checked.
I'm using IdentifiedArray in a lot of other places in struct states and haven't experienced any crash – so this might be related, I guess?

Here is a simplified version of my class:

public final class FriendManagerState: Equatable {
  public internal(set) var friends: IdentifiedArrayOf<FriendProfileState>

  public init(
    friends: IdentifiedArrayOf<FriendProfileState>
  ) {
    self.friends = friends
  }

  public static func == (
    lhs: FriendManagerState, rhs: FriendManagerState
  ) -> Bool {
    // This is the method invoked at step 11 of the stacktrace

    // Also crashes with `lhs.friends.elementsEqual(rhs.friends.elements)`
    return lhs.friends == rhs.friends
  }
}

I'm not doing anything fancy with the array, the only methods I'm calling are updateOrInsert, update, append, sort – and everything is performed on a single queue.


Version: 0.3.1
Xcode 13.0 (release)
Swift 5.5 (swiftlang-1300.0.31.1 clang-1300.0.29.1)
The crash occurs on iOS 15.0 & 15.1, I haven't been able to test on MacOS.

I'm happy to provide more details if needed – also if this turns out to be a TCA issue, I'll gladly move this issue to its repo.

@HarshilShah
Copy link

Not sure if it’s the same bug but we’re also seeing a similar crash on updateOrAppend. Here’s the stacktrace:

#0	0x000000018b16f32c in _swift_runtime_on_report ()
#1	0x000000018b1dfe7c in _swift_stdlib_reportFatalErrorInFile ()
#2	0x000000018aec6aa4 in closure #1 in closure #1 in closure #1 in _assertionFailure(_:_:file:line:flags:) ()
#3	0x000000018aec6848 in closure #1 in closure #1 in _assertionFailure(_:_:file:line:flags:) ()
#4	0x000000018aec61c8 in _assertionFailure(_:_:file:line:flags:) ()
#5	0x000000018aec64bc in _fatalErrorMessage(_:_:file:line:flags:) ()
#6	0x000000018b0db8f8 in UnsafeBufferPointer.subscript.read ()
#7	0x000000018b0db768 in protocol witness for Collection.subscript.read in conformance UnsafeBufferPointer<τ_0_0> ()
#8	0x00000001030fed8c in RandomAccessCollection.subscript.getter at [...]/checkouts/swift-collections/Sources/OrderedCollections/Utilities/RandomAccessCollection+Offsets.swift:28
#9	0x00000001030bca30 in _HashTable.UnsafeHandle._find<τ_0_0>(_:in:) at [...]/checkouts/swift-collections/Sources/OrderedCollections/HashTable/_HashTable+UnsafeHandle.swift:299
#10	0x00000001030fceb0 in closure #1 in closure #1 in OrderedSet._find_inlined(_:) at [...]/checkouts/swift-collections/Sources/OrderedCollections/OrderedSet/OrderedSet.swift:396
#11	0x00000001030fcf14 in thunk for @callee_guaranteed (@unowned _HashTable.UnsafeHandle) -> (@unowned Int?, @unowned _HashTable.Bucket, @error @owned Error) ()
#12	0x00000001030fea20 in partial apply for thunk for @callee_guaranteed (@unowned _HashTable.UnsafeHandle) -> (@unowned Int?, @unowned _HashTable.Bucket, @error @owned Error) ()
#13	0x00000001030c2904 in closure #1 in _HashTable.read<τ_0_0>(_:) at [...]/checkouts/swift-collections/Sources/OrderedCollections/HashTable/_HashTable.swift:151
#14	0x00000001030c2fec in partial apply for closure #1 in _HashTable.read<τ_0_0>(_:) ()
#15	0x000000018afb700c in ManagedBuffer.withUnsafeMutablePointers<τ_0_0>(_:) ()
#16	0x00000001030c2828 in _HashTable.read<τ_0_0>(_:) at [...]/checkouts/swift-collections/Sources/OrderedCollections/HashTable/_HashTable.swift:149
#17	0x00000001030fcd20 in closure #1 in OrderedSet._find_inlined(_:) at [...]/checkouts/swift-collections/Sources/OrderedCollections/OrderedSet/OrderedSet.swift:395
#18	0x00000001030fcfac in thunk for @callee_guaranteed (@unowned UnsafeBufferPointer<τ_0_0>) -> (@unowned Int?, @unowned _HashTable.Bucket, @error @owned Error) ()
#19	0x00000001030fe4b4 in partial apply for thunk for @callee_guaranteed (@unowned UnsafeBufferPointer<τ_0_0>) -> (@unowned Int?, @unowned _HashTable.Bucket, @error @owned Error) ()
#20	0x000000018aea9690 in ContiguousArray.withUnsafeBufferPointer<τ_0_0>(_:) ()
#21	0x00000001030fca4c in OrderedSet._find_inlined(_:) at [...]/checkouts/swift-collections/Sources/OrderedCollections/OrderedSet/OrderedSet.swift:391
#22	0x00000001030fc8bc in OrderedSet._find(_:) at [...]/checkouts/swift-collections/Sources/OrderedCollections/OrderedSet/OrderedSet.swift:385
#23	0x00000001030d9e20 in OrderedDictionary.updateValue(_:forKey:) at [...]/checkouts/swift-collections/Sources/OrderedCollections/OrderedDictionary/OrderedDictionary.swift:541
#24	0x00000001030b22b8 in IdentifiedArray.updateOrAppend(_:) at [...]/checkouts/swift-identified-collections/Sources/IdentifiedCollections/IdentifiedArray/IdentifiedArray+Insertions.swift:67

It crashes reliably on an iOS 15 simulator or an iPhone 6s running iOS 15.0.2 (both debug)

@stephencelis stephencelis added the apple bug Something isn't working due to a bug on Apple's platforms. label Oct 19, 2021
@KaiOelfke
Copy link
Contributor

FYI: There's a PR with a fix now: apple/swift-collections#123

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
apple bug Something isn't working due to a bug on Apple's platforms.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants