SwiftyStoreKit icon indicating copy to clipboard operation
SwiftyStoreKit copied to clipboard

Urgent: PaymentQueueController crash in IOS 12

Open endogenesis opened this issue 7 years ago • 7 comments

Platform

  • iOS 12

In app purchase type

  • Auto-Renewable Subscription

Environment

  • Production

Version

0.13.2

Issue summary

Sometime application crashes on restore and startPayment. Repoduced on IOS 12. Looks like unowned let paymentQueue: PaymentQueue in PaymentQueueController.swift deallocated when we trying to read it.

Report

#0. Crashed: com.apple.main-thread 0 libsystem_kernel.dylib 0x1c7c83104 __pthread_kill + 8 1 libsystem_pthread.dylib 0x1c7cff020 pthread_kill$VARIANT$mp + 380 2 libsystem_c.dylib 0x1c7bdad78 abort + 140 3 libswiftCore.dylib 0x10139d9d0 swift_vasprintf(char**, char const*, char*) + 54 4 libswiftCore.dylib 0x10139db0c swift::swift_abortRetainUnowned(void const*) + 32 5 libswiftCore.dylib 0x1013d7b2c swift_unknownUnownedTakeStrong + 70 6 SwiftyStoreKit 0x100fca854 PaymentQueueController.startPayment(:) (PaymentQueueController.swift:131) 7 SwiftyStoreKit 0x100fd7cd4 closure #1 in SwiftyStoreKit.purchaseProduct(:quantity:atomically:applicationUsername:simulatesAskToBuyInSandbox:completion:) () 8 SwiftyStoreKit 0x100fddbe0 partial apply for closure #1 in SwiftyStoreKit.purchaseProduct(:quantity:atomically:applicationUsername:simulatesAskToBuyInSandbox:completion:) () 9 SwiftyStoreKit 0x100fd1238 partial apply for thunk for @escaping @callee_guaranteed (@guaranteed RetrieveResults) -> () () 10 SwiftyStoreKit 0x100fcf114 closure #1 in ProductsInfoController.retrieveProductsInfo(:completion:) (ProductsInfoController.swift:68) 11 SwiftyStoreKit 0x100fbfc40 partial apply for closure #1 in InAppProductQueryRequest.performCallback(_:) () 12 SwiftyStoreKit 0x100fc8e98 thunk for @escaping @callee_guaranteed () -> () () 13 libdispatch.dylib 0x1c7b256c8 _dispatch_call_block_and_release + 24 14 libdispatch.dylib 0x1c7b26484 _dispatch_client_callout + 16 15 libdispatch.dylib 0x1c7ad29a4 _dispatch_main_queue_callback_4CF$VARIANT$mp + 1068 16 CoreFoundation 0x1c807dce4 CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE + 12 17 CoreFoundation 0x1c8078bac __CFRunLoopRun + 1964 18 CoreFoundation 0x1c80780e0 CFRunLoopRunSpecific + 436 19 GraphicsServices 0x1ca2f1584 GSEventRunModal + 100 20 UIKitCore 0x1f5288c00 UIApplicationMain + 212 21 MyApplication 0x1003a5d38 main (main.m:14) 22 libdyld.dylib 0x1c7b36bb4 start + 4

#Crashed: com.apple.main-thread 0 libsystem_kernel.dylib 0x1aeb1f104 __pthread_kill + 8 1 libsystem_pthread.dylib 0x1aeb9b020 pthread_kill$VARIANT$mp + 380 2 libsystem_c.dylib 0x1aea76d78 abort + 140 3 libswiftCore.dylib 0x1017399d0 swift_vasprintf(char**, char const*, char*) + 54 4 libswiftCore.dylib 0x101739b0c swift::swift_abortRetainUnowned(void const*) + 32 5 libswiftCore.dylib 0x101773b2c swift_unknownUnownedTakeStrong + 70 6 SwiftyStoreKit 0x101374e98 static SwiftyStoreKit.restorePurchases(atomically:applicationUsername:completion:) (PaymentQueueController.swift:143) 7 MyApplication 0x1009ad060 protocol witness for Store.restorePurchases(completion:) in conformance SwiftyStoreAdapter () 8 MyApplication 0x10099ff40 closure #1 in PurchaseController.restorePurchases(completion:) () 9 MyApplication 0x1008a7bb4 thunk for @escaping @callee_guaranteed () -> () () 10 libdispatch.dylib 0x1ae9c16c8 _dispatch_call_block_and_release + 24 11 libdispatch.dylib 0x1ae9c2484 _dispatch_client_callout + 16 12 libdispatch.dylib 0x1ae96e9a4 _dispatch_main_queue_callback_4CF$VARIANT$mp + 1068 13 CoreFoundation 0x1aef19ce4 CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE + 12 14 CoreFoundation 0x1aef14bac __CFRunLoopRun + 1964 15 CoreFoundation 0x1aef140e0 CFRunLoopRunSpecific + 436 16 GraphicsServices 0x1b118d584 GSEventRunModal + 100 17 UIKitCore 0x1dc274c00 UIApplicationMain + 212 18 MyApplication 0x1007f36f0 main (main.m:14) 19 libdyld.dylib 0x1ae9d2bb4 start + 4

endogenesis avatar Mar 01 '19 11:03 endogenesis

I'm getting this as well:

Crashed: com.apple.main-thread SIGABRT ABORT 0x0000000185ce20dc

0  libsystem_kernel.dylib         0x185ce20dc __pthread_kill + 8
1  libsystem_pthread.dylib        0x185d5b094 pthread_kill$VARIANT$mp + 380
2  libsystem_c.dylib              0x185c3bea8 abort + 140
3  libswiftCore.dylib             0x1b44652a8 swift_vasprintf(char**, char const*, char*) + 54
4  libswiftCore.dylib             0x1b44653e4 swift::swift_abortRetainUnowned(void const*) + 32
5  libswiftCore.dylib             0x1b44aa7a8 swift_unknownObjectUnownedTakeStrong + 70
6  SwiftyStoreKit                 0x105c975e4 PaymentQueueController.startPayment(_:) + 132 (PaymentQueueController.swift:132)

RamblinWreck77 avatar Jul 08 '19 22:07 RamblinWreck77

Some context:

-I've been using this pod for forever, never had this crash

-Prior to this update I forced users to auth on app launch/login. .completeTransations() is called on every app launch, and that code didn't change.

-What DID change was I now have an "offline mode", and allow users into the app if they have previously cached credentials albeit with reduced functionality.

Now, the crash appears to be occurring in startPayment and I see the assert:

let message = "SwiftyStoreKit.completeTransactions() must be called when the app launches."
        assert(completeTransactionsController.completeTransactions != nil, message)

So the only thing I can assume is that users must be trying to start payment from offline mode and somehow that's interacting with this.

RamblinWreck77 avatar Jul 08 '19 22:07 RamblinWreck77

Another report:

Crashed: com.apple.main-thread
0  libsystem_kernel.dylib         0x18a0b20dc __pthread_kill + 8
1  libsystem_pthread.dylib        0x18a12b094 pthread_kill$VARIANT$mp + 380
2  libsystem_c.dylib              0x18a00bea8 abort + 140
3  libswiftCore.dylib             0x1b7a5c2a8 swift_vasprintf(char**, char const*, char*) + 54
4  libswiftCore.dylib             0x1b7a5c3e4 swift::swift_abortRetainUnowned(void const*) + 32
5  libswiftCore.dylib             0x1b7aa17a8 swift_unknownObjectUnownedTakeStrong + 70
6  SwiftyStoreKit                 0x101ed35e4 PaymentQueueController.startPayment(_:) + 132 (PaymentQueueController.swift:132)
7  SwiftyStoreKit                 0x101ee15f4 closure #1 in SwiftyStoreKit.purchaseProduct(_:quantity:atomically:applicationUsername:simulatesAskToBuyInSandbox:completion:) + 68 (SwiftyStoreKit.swift:68)
8  SwiftyStoreKit                 0x101ee56d4 partial apply for closure #1 in SwiftyStoreKit.purchaseProduct(_:quantity:atomically:applicationUsername:simulatesAskToBuyInSandbox:completion:) (<compiler-generated>)
9  SwiftyStoreKit                 0x101ed90a0 partial apply for thunk for @escaping @callee_guaranteed (@guaranteed RetrieveResults) -> () (<compiler-generated>)
10 SwiftyStoreKit                 0x101ed6f78 closure #1 in ProductsInfoController.retrieveProductsInfo(_:completion:) + 66 (ProductsInfoController.swift:66)
11 SwiftyStoreKit                 0x101ec7258 partial apply for closure #1 in InAppProductQueryRequest.performCallback(_:) + 76 (InAppProductQueryRequest.swift:76)
12 SwiftyStoreKit                 0x101ed0f34 thunk for @escaping @callee_guaranteed () -> () (<compiler-generated>)
13 libdispatch.dylib              0x189f54a38 _dispatch_call_block_and_release + 24
14 libdispatch.dylib              0x189f557d4 _dispatch_client_callout + 16
15 libdispatch.dylib              0x189f03004 _dispatch_main_queue_callback_4CF$VARIANT$mp + 1068
16 CoreFoundation                 0x18a4a5ec0 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12
17 CoreFoundation                 0x18a4a0df8 __CFRunLoopRun + 1924
18 CoreFoundation                 0x18a4a0354 CFRunLoopRunSpecific + 436
19 GraphicsServices               0x18c6a079c GSEventRunModal + 104
20 UIKitCore                      0x1b6913b68 UIApplicationMain + 212
21 App                           0x100943968 main + 32 (UI.swift:32)
22 libdyld.dylib                  0x189f668e0 start + 4

RamblinWreck77 avatar Jul 12 '19 13:07 RamblinWreck77

@bizz84 Sorry to bother you, but this is occurring when users try and make a purchase.

Any ideas?

RamblinWreck77 avatar Jul 12 '19 13:07 RamblinWreck77

I've made some more progress on this.

The root cause seems to be a thread safety issue. My network calls are on a separate queue, and when the user gets an internet connection my code checks to see if IAPs have been loaded from the store. If not, it makes a call to SwiftyStoreKit.retrieveProductsInfo

So on Thread 0: -App init -IAP Setup is called, Swifty Store kit is setup from a helper struct (complete transactions, etc etc, the retrieve products called)

Thread 2: -User gets an internet connection -Maybe products haven't loaded yet, and no cached products are available. If this happens in the right order then: -SwiftyStoreKit.retrieveProductsInfo gets called from thread 2, while thread 0 is doing the above

fileprivate func retrieveProductsInfo(_ productIds: Set<String>, completion: @escaping (RetrieveResults) -> Void) {
        return productsInfoController.retrieveProductsInfo(productIds, completion: completion)
    }

gets a crash, with the lowest level being:

#0	(null) in specialized _NativeDictionary.setValue(_:forKey:isUnique:) ()

So I'd suspect the problem is a lack of thread safety w/a storage dictionary.

I'm attempting to solve this with an improved model in my app, as well as wrapping all calls to SwiftyStoreKit in main thread async dispatches. If this resolves the issue I will report back.

RamblinWreck77 avatar Jul 14 '19 14:07 RamblinWreck77

inflightRequests should be thread safe

astrokin avatar Sep 22 '19 21:09 astrokin

any news?

caggiulio avatar Aug 20 '21 16:08 caggiulio