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: Installation.current setter not thread safe #443

Open
alessdiimperio opened this issue Sep 27, 2023 · 1 comment
Open

Crash: Installation.current setter not thread safe #443

alessdiimperio opened this issue Sep 27, 2023 · 1 comment

Comments

@alessdiimperio
Copy link

New Issue Checklist

Issue Description

We store user information on the installation object. And when modifying or changing the data we save the installation.
The issue seems to be that the underlying InMemoryKeyValueStore setter does not support concurrency.

we have services and managers that handle different parts of our app and for example if a user logs in we set a pointer on the installation with the current user and save it async.
We also set the push permissions state async and save
we also set the channels and device token async and save
we check analytics tracking consent and if accepted async and save

now not all of these are fired off at the same time but in some cases 2-3 of these saves may be executed concurrently on app startup which causes the setter to be called concurrently and attempt to write to the underlying dictionary at the same time causing a runtime error as write operations on a dictionary may not be done concurrently.

mutating func set(_ object: T, for key: String) throws where T: Encodable {
let data = try encoder.encode(object)
storage[key] = data <- this is where it crashes
}

Perhaps modifying the storage[:] dictionary should be done on a custom serial queue so it cannot be modified concurrently on different threads?

Steps to reproduce

for index in 1..<10 {
Task.detached {
try await installation.save()
}
}

Actual Outcome

It crashes with runtime exception

Expected Outcome

Should not crash

Environment

Client

  • Parse Swift SDK version: 4.14.2
  • Xcode version: 14.3.1
  • Operating system (iOS, macOS, watchOS, etc.): iOS
  • Operating system version: 17.0.0

Server

  • Parse Server version: 4.3
  • Operating system: linux
  • Local or remote host (AWS, Azure, Google Cloud, Heroku, Digital Ocean, etc): local

Database

  • System (MongoDB or Postgres): SQL
  • Database version: :shrug:
  • Local or remote host (MongoDB Atlas, mLab, AWS, Azure, Google Cloud, etc): local

Logs

#0 0x0000000113814acb in objc_msgSend ()
#1 0x000000011f261b9c in Dictionary.Variant.setValue(:forKey:) ()
#2 0x000000011f224ae8 in Dictionary.subscript.setter ()
#3 0x0000000116428ecd in InMemoryKeyValueStore.set<τ_0_0>(:for:) at /Users/alessio.diimperio/Documents/ios/Pods/ParseSwift/Sources/ParseSwift/Storage/ParseKeyValueStore.swift:61
#4 0x00000001164291bd in protocol witness for ParsePrimitiveStorable.set<τ_0_0>(
:for:) in conformance InMemoryKeyValueStore ()
#5 0x000000011651af87 in ParseStorage.set<τ_0_0>(:for:) at /Users/alessio.diimperio/Documents/ios/Pods/ParseSwift/Sources/ParseSwift/Storage/ParseStorage.swift:56
#6 0x00000001163ddc00 in static ParseInstallation.currentContainer.setter at /Users/alessio.diimperio/Documents/ios/Pods/ParseSwift/Sources/ParseSwift/Objects/ParseInstallation.swift:257
#7 0x00000001163decbf in static ParseInstallation.current.setter at /Users/alessio.diimperio/Documents/ios/Pods/ParseSwift/Sources/ParseSwift/Objects/ParseInstallation.swift:302
#8 0x00000001163e3b99 in static ParseInstallation.updateKeychainIfNeeded(
:deleting:) at /Users/alessio.diimperio/Documents/ios/Pods/ParseSwift/Sources/ParseSwift/Objects/ParseInstallation.swift:495
#9 0x0000000116417736 in ParseInstallation.command(method:ignoringCustomObjectIdConfig:options:callbackQueue:) at /Users/alessio.diimperio/Documents/ios/Pods/ParseSwift/Sources/ParseSwift/Objects/ParseInstallation+async.swift:356
#10 0x00000001163e76b0 in closure #1 in ParseInstallation.save(ignoringCustomObjectIdConfig:options:callbackQueue:completion:) at /Users/alessio.diimperio/Documents/ios/Pods/ParseSwift/Sources/ParseSwift/Objects/ParseInstallation.swift:699
#11 0x00000001163e8570 in partial apply for closure #1 in ParseInstallation.save(ignoringCustomObjectIdConfig:options:callbackQueue:completion:) ()
#12 0x0000000116299580 in thunk for @escaping @callee_guaranteed @sendable @async () -> (@out τ_0_0) ()
#13 0x000000011629a4b0 in partial apply for thunk for @escaping @callee_guaranteed @sendable @async () -> (@out τ_0_0) ()

@parse-github-assistant
Copy link

Thanks for opening this issue!

  • 🚀 You can help us to fix this issue faster by opening a pull request with a failing test. See our Contribution Guide for how to make a pull request, or read our New Contributor's Guide if this is your first time contributing.

@parse-community parse-community deleted a comment from bcbeta Sep 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant