liveview-native / liveview-client-swiftui

MIT License
379 stars 39 forks source link

[Bug]: `StylesheetCache` is not thread-safe #1460

Closed nighthawk closed 2 months ago

nighthawk commented 2 months ago

What happened?

I'm experiencing occasional runtime crashes from StylesheetCache.

It's accessed from LiveSessionCoordinator.connect() like this:

            async let stylesheet = withThrowingTaskGroup(of: Stylesheet<R>.self) { group in
                for style in try doc.select("Style") {
                    guard let url = URL(string: try style.attr("url"), relativeTo: url)
                    else { continue }
                    group.addTask {
                        if let cachedStylesheet = StylesheetCache[for: url, registry: R.self] {
                            return cachedStylesheet
                        } else {
                            let (data, response) = try await self.urlSession.data(from: url)
                            guard let contents = String(data: data, encoding: .utf8)
                            else { return Stylesheet<R>(content: [], classes: [:]) }
                            let stylesheet = try Stylesheet<R>(from: contents, in: .init())
                            StylesheetCache[for: url, registry: R.self] = stylesheet // <= 💥
                            return stylesheet
                        }
                    }
                }
                return try await group.reduce(Stylesheet<R>(content: [], classes: [:])) { result, next in
                    return result.merge(with: next)
                }
            }

This then crashes as StylesheetCache is not thread-safe:

image

It's probably better to implement this as an actor or similar.

I'm running in Swift 5.0 language mode, i.e., without the strict 6.0 concurrency.

Library Version

0.3.0

Xcode Version

16.0

Swift Version

6.0

On which device or simulator are you running into the problem?

iPad

Target Device Operating System Version

18.0

Relevant log output

[Socket] SwiftPhoenixClient: Socket attempting to reconnect