swift-composable-architecture: Crash in Store.send(_:originatingFrom:)

Description

We are seeing a crash in Store.send(_:originatingFrom:), as shown by this Crashlytics call stack:

Screen Shot 2022-12-13 at 10 56 57 AM Screen Shot 2022-12-13 at 10 57 41 AM

It’s difficult to see how this could happen, given that self.bufferedActions is protected by an !self.bufferedActions.isEmpty check here:

      if !self.bufferedActions.isEmpty {
        if let task = self.send(
          self.bufferedActions.removeLast(), originatingFrom: originatingAction
        ) {
          tasks.wrappedValue.append(task)
        }
      }

We are using swift-composable-architecture v0.45.0, although it appears the code from v0.45.0 is the same as the code in the main branch.

Checklist

  • I have determined whether this bug is also reproducible in a vanilla SwiftUI project.
  • If possible, I’ve reproduced the issue using the main branch of this package.
  • This issue hasn’t been addressed in an existing GitHub issue or discussion.

Expected behavior

No crash.

Actual behavior

See the Crashlytics call stacks above.

Steps to reproduce

It is intermittent, and does not happen very often.

The Composable Architecture version information

0.45.0

Destination operating system

No response

Xcode version information

Xcode 14.1

Swift Compiler version information

ehyche in ~/src/github/noom/coach-ios (ehyche/ARM-778-cached-or-fresh) > xcrun swiftc --version
swift-driver version: 1.62.15 Apple Swift version 5.7.1 (swiftlang-5.7.1.135.3 clang-1400.0.29.51)
Target: arm64-apple-macosx12.0

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 20 (8 by maintainers)

Most upvoted comments

The times we’ve seen this kind of access in the past is when somewhat dangerous things were being done, like having a ViewStore or send closure injected into a reducer via action/environment. If you are interacting with the store in such a way we strongly recommend refactoring away from this kind of pattern. Ideally a reducer has no way of interfacing with its backing store directly.

As an aside, please let us know if newer versions of TCA help. We’re constantly fixing small bugs, including a recent release-only one: #1881.

Thank you for such quick feedback. I’m downloading Xcode 14.2. Will see if it fixes the issue.

Unfortunately not, I‘m having the exact same issue with incremental builds.

two threads sending actions at the same time, and mutating the same storage at the same time

@stephencelis any advice on how to catch these situations? We are seeing the same as OP.