Summary
InMemoryNormalizedCache is not thread-safe when multiple GraphQL queries/mutations execute concurrently. When multiple threads attempt to merge records into the cache simultaneously, it causes memory corruption crashes with the error: "___BUG_IN_CLIENT_OF_LIBMALLOC_POINTER_BEING_FREED_WAS_NOT_ALLOCATED".
The crash occurs in RecordSet.merge(record:) when Dictionary operations are performed concurrently without proper synchronization.
Version
2.0.4
Steps to reproduce the behavior
- Create an ApolloStore with default InMemoryNormalizedCache
- Execute multiple GraphQL queries/mutations concurrently from different threads (e.g., using async/await with different Task contexts)
- These operations will trigger cache merge operations simultaneously
- The app will crash with memory corruption error
Logs
Crashed: com.apple.root.user-initiated-qos.cooperative
0 libsystem_kernel.dylib 0xb0cc __pthread_kill + 8
1 libsystem_pthread.dylib 0x7810 pthread_kill + 268
2 libsystem_c.dylib 0x77f64 abort + 124
3 libsystem_malloc.dylib 0x15a64 malloc_vreport + 892
4 libsystem_malloc.dylib 0x156dc malloc_report + 64
5 libsystem_malloc.dylib 0x9714 ___BUG_IN_CLIENT_OF_LIBMALLOC_POINTER_BEING_FREED_WAS_NOT_ALLOCATED + 76
6 libswiftCore.dylib 0x27e60 <redacted> + 56
7 libswiftCore.dylib 0x28a7c <redacted> + 152
8 MyApp 0x39f7fc specialized _NativeDictionary.copy() + 4305451004
9 MyApp 0x39edf4 specialized _NativeDictionary.setValue(_:forKey:isUnique:) + 4305448436
10 MyApp 0x3a49c4 RecordSet.merge(record:) + 4305471940
11 MyApp 0x3a375c RecordSet.merge(records:) + 4305467228
12 MyApp 0x39e6d0 protocol witness for NormalizedCache.merge(records:) in conformance InMemoryNormalizedCache + 4305446608
13 libswift_Concurrency.dylib 0x62d58 <redacted> + 288
14 libswift_Concurrency.dylib 0x641cc <redacted> + 156
15 libdispatch.dylib 0x13f48 _dispatch_root_queue_drain + 364
16 libdispatch.dylib 0x146fc _dispatch_worker_thread2 + 180
17 libsystem_pthread.dylib 0x137c _pthread_wqthread + 232
18 libsystem_pthread.dylib 0x8c0 start_wqthread + 8
Anything else?
No response
Summary
InMemoryNormalizedCache is not thread-safe when multiple GraphQL queries/mutations execute concurrently. When multiple threads attempt to merge records into the cache simultaneously, it causes memory corruption crashes with the error: "___BUG_IN_CLIENT_OF_LIBMALLOC_POINTER_BEING_FREED_WAS_NOT_ALLOCATED".
The crash occurs in RecordSet.merge(record:) when Dictionary operations are performed concurrently without proper synchronization.
Version
2.0.4
Steps to reproduce the behavior
Logs
Anything else?
No response