fix: serialize updateLastUseDate with messageQueue on background entry#680
Conversation
PR SummaryMedium Risk Overview Adds new unit tests that stress concurrent reads/writes to Written by Cursor Bugbot for commit 55c51fe. This will update automatically on new commits. Configure here. |
📦 SDK Size Impact ReportMeasures how much the SDK adds to an app's size (with-SDK minus without-SDK).
➡️ SDK size impact change is minimal. Raw measurementsTarget branch (main): {"baseline_app_size_kb":84,"baseline_executable_size_bytes":75464,"with_sdk_app_size_kb":1944,"with_sdk_executable_size_bytes":76360,"sdk_impact_kb":1860,"sdk_executable_impact_bytes":896,"xcframework_size_kb":9720}This PR: {"baseline_app_size_kb":84,"baseline_executable_size_bytes":75464,"with_sdk_app_size_kb":1944,"with_sdk_executable_size_bytes":76360,"sdk_impact_kb":1860,"sdk_executable_impact_bytes":896,"xcframework_size_kb":9716} |
Background
EXC_BAD_ACCESS KERN_INVALID_ADDRESSinobjc_retainduringCFPrefsSource mergeIntoDictionary, triggered byNSUserDefaults objectForKey:.UIApplicationDidEnterBackgroundNotificationfires,MPBackendControllerdispatches its background work (which readsUserDefaultsviaMPPersistenceController.mpId) to the serialmessageQueue, whileMPStateMachinecalledupdateLastUseDate:synchronously on the main thread — writing to the sameUserDefaults. The concurrent read + write onCFPrefsSource's internal dictionary caused the crash.What Has Changed
mParticle-Apple-SDK/MPStateMachine.m—handleApplicationDidEnterBackground:now dispatchesupdateLastUseDate:tomessageQueueviadispatch_async, serializing the write withMPBackendController's concurrent read. The_launchDateivar is captured into a local before the block to avoid capturingself. The termination handler (handleApplicationWillTerminate:) remains synchronous becauseMPBackendControllerdoes not observe that notification (no race) anddispatch_asyncrisks losing the write if the process is killed.UnitTests/ObjCTests/MPStateMachineTests.m— Added 3 regression tests:testUpdateLastUseDateSerializedWithMessageQueueWork: 500-iteration stress test simulating the fixed pattern (bothupdateLastUseDateand backend controller work onmessageQueuewith concurrent reads from global queues).testSubscriptAccessorThreadSafety: 1000-iteration concurrent read/write stress test onMPUserDefaultssubscript accessors.testUpdateLastUseDateWithNilDate: edge case verifyingnildate produces@0rather than crashing.Additional Notes
Reported crash 1
Checklist
Reference Issue (For employees only. Ignore if you are an outside contributor)