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

Crash when using @Shared appStorage during certain conditions #3311

Open
1 of 3 tasks
zachwaugh opened this issue Aug 26, 2024 · 6 comments · May be fixed by #3437
Open
1 of 3 tasks

Crash when using @Shared appStorage during certain conditions #3311

zachwaugh opened this issue Aug 26, 2024 · 6 comments · May be fixed by #3437
Labels
bug Something isn't working due to a bug in the library.

Comments

@zachwaugh
Copy link

Description

I'm seeing a crash with a similar backtrace to #3247, but appears not to be caused by a thread issue.

I'm using a @shared appStorage key roughly like:

@Shared(.appStorage("key")) var isEnabled: Bool = true

When launching the app it crashes. I'm still working on a simplified repro but having a hard time isolating the exact code causing the problem, but thought I'd post the issue in case anyone else has an idea.

Screenshot 2024-08-26 at 12 24 36 PM

If you look at the backtrace, it appears an NSAttributedString is performing layout (which isn't in my code) which triggers an NSUserDefault update which in turn causes the @Shared storage to update immediately during the same render cycle?The only relevant logs related to the crash are:

precondition failure: setting value during update: 219864
Screenshot 2024-08-26 at 12 25 55 PM

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 response

Actual behavior

No response

Steps to reproduce

No response

The Composable Architecture version information

1.13.1

Destination operating system

iOS 17.5

Xcode version information

Xcode 15.4

Swift Compiler version information

No response

@zachwaugh zachwaugh added the bug Something isn't working due to a bug in the library. label Aug 26, 2024
@mbrandonw
Copy link
Member

Hi @zachwaugh, thanks for the report, but unfortunately without a repro it's hard to diagnose. The precondition failure message ("precondition failure: setting value during update") seems to clearly describe the problem: in the act of executing a view's body a value is being mutated. If you do this with @State, SwiftUI will even produce a purple runtime warning letting you know this isn't a good thing to do.

Only one idea comes to mind. In the stack trace we have mainActorNow to execute some work on the main thread as soon as possible, i.e. synchronously if already on the main thread, otherwise DispatchQueue.main.async. If instead we always incurred a thread hop, then that would guarantee the state does not change while in a view body.

Are you in a position to reproduce this precondition easily in your local environment? Would you be willing to try replacing mainActorNow with DispatchQueue.main.async and see if that fixes things?

@andreyz
Copy link
Contributor

andreyz commented Aug 30, 2024

Getting a similarily suspicious crash on writing to FileStorageKey backed Shared.
The line open #1 <A><A1, B1>(_:) in Shared.currentValue.getter seems to be same as in the crash above.

We started getting this crash after updating to 1.14.0 from 1.12.1.

#0	(null) in std::__1::__function::__func<_gatherGenericParameters(swift::TargetContextDescriptor<swift::InProcess> const*, __swift::__runtime::llvm::ArrayRef<swift::MetadataOrPack>, swift::TargetMetadata<swift... ()
#1	(null) in swift_getTypeByMangledNameImpl(swift::MetadataRequest, __swift::__runtime::llvm::StringRef, void const* const*, std::__1::function<void const* (unsigned int, unsigned int)>, std::__1::function<swif... ()
#2	(null) in swift_getTypeByMangledName ()
#3	(null) in swift::_checkGenericRequirements(__swift::__runtime::llvm::ArrayRef<swift::TargetGenericRequirementDescriptor<swift::InProcess>>, __swift::__runtime::llvm::SmallVectorImpl<void const*>&, std::__1::... ()
#4	(null) in _gatherGenericParameters(swift::TargetContextDescriptor<swift::InProcess> const*, __swift::__runtime::llvm::ArrayRef<swift::MetadataOrPack>, swift::TargetMetadata<swift::InProcess> const*, __swift:... ()
#5	(null) in (anonymous namespace)::DecodedMetadataBuilder::createBoundGenericType(swift::TargetContextDescriptor<swift::InProcess> const*, __swift::__runtime::llvm::ArrayRef<swift::MetadataOrPack>, swift::Meta... ()
#6	(null) in swift::Demangle::__runtime::TypeDecoder<(anonymous namespace)::DecodedMetadataBuilder>::decodeMangledType(swift::Demangle::__runtime::Node*, unsigned int, bool) ()
#7	(null) in swift_getTypeByMangledNodeImpl(swift::MetadataRequest, swift::Demangle::__runtime::Demangler&, swift::Demangle::__runtime::Node*, void const* const*, std::__1::function<void const* (unsigned int, u... ()
#8	(null) in swift_getTypeByMangledNode ()
#9	(null) in swift_getTypeByMangledNameImpl(swift::MetadataRequest, __swift::__runtime::llvm::StringRef, void const* const*, std::__1::function<void const* (unsigned int, unsigned int)>, std::__1::function<swif... ()
#10	(null) in swift_getTypeByMangledName ()
#11	(null) in swift_getTypeByMangledNameInEnvironment ()
#12	(null) in _resolveKeyPathGenericArgReference(_:genericEnvironment:arguments:) ()
#13	(null) in specialized _walkKeyPathPattern<A>(_:walker:) ()
#14	(null) in _getKeyPathClassAndInstanceSizeFromPattern(_:_:) ()
#15	(null) in _swift_getKeyPath(pattern:arguments:) ()
#16	0x0000000104a61e34 in ValueReference.value.getter at ComposableArchitecture/SharedState/References/ValueReference.swift:355
#17	0x0000000104a66da0 in open #1 <A><A1, B1>(_:) in Shared.currentValue.getter at ComposableArchitecture/SharedState/Shared.swift:260
#18	(null) in Shared._wrappedValue.getter ()

@mbrandonw
Copy link
Member

Hi @andreyz, your crash does not seem to be related to the one discussed here. The one in this issue has stack frames with AG::Graph, which is from AttributeGraph that powers SwiftUI. Your crash is just pure Swift code, and has something to do with opening existentials and/or mangling type names.

And as always, a reproduction is the best way to get help on this.

stephencelis added a commit that referenced this issue Oct 9, 2024
I think we're finding that synchronous subscriptions can be problematic
depending on the strategy, for example as we're seeing with user
defaults notifications being fired by attributed string's internals.

Fixes #3311.
@stephencelis stephencelis linked a pull request Oct 9, 2024 that will close this issue
@stephencelis
Copy link
Member

@zachwaugh Can you give #3437 a try and see if it addresses things for you?

@ajason
Copy link

ajason commented Oct 23, 2024

Same issue when using @Shared(.appStorage) in multiple features, which causes a crash at startup.
I tried the shared-async-subscription branch, and the problem no longer appears on my end.

@github-staff github-staff deleted a comment from Lxx-c Oct 23, 2024
@github-staff github-staff deleted a comment from Lxx-c Oct 23, 2024
@zachwaugh
Copy link
Author

@stephencelis I've removed use of @Shared from my app after hitting a few crashes, so I don't have it in there at the moment to test. But I'll go back to an earlier commit when I have some time and see if it's resolved. Thanks for looking into it!

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

Successfully merging a pull request may close this issue.

8 participants
@stephencelis @zachwaugh @mbrandonw @andreyz @ajason and others