PromiseKit: EmptyBox.seal crash

We see this crash in our app on AppStore, using PromiseKit 6.2.1:

Thread 5 Crashed:
0   libsystem_malloc.dylib        	0x000000018763355c nanov2_allocate_from_block$VARIANT$mp + 4 (nanov2_malloc.c:1942)
1   libsystem_malloc.dylib        	0x00000001876329d0 nanov2_allocate$VARIANT$mp + 140 (nanov2_malloc.c:2395)
2   libsystem_malloc.dylib        	0x00000001876328f4 nanov2_malloc$VARIANT$mp + 60 (nanov2_malloc.c:922)
3   libsystem_malloc.dylib        	0x00000001876419a0 malloc_zone_malloc + 156 (malloc.c:1454)
4   libsystem_malloc.dylib        	0x00000001876423b0 malloc + 32 (malloc.c:1720)
5   libswiftCore.dylib            	0x0000000104931f80 0x104684000 + 2809728
6   libswiftCore.dylib            	0x0000000104932000 0x104684000 + 2809856
7   libswiftDispatch.dylib        	0x0000000104b9bcac 0x104b88000 + 81068
8   libswiftDispatch.dylib        	0x0000000104b973e0 0x104b88000 + 62432
9   libswiftDispatch.dylib        	0x0000000104b97d74 0x104b88000 + 64884
10  PromiseKit                    	0x00000001031daf14 EmptyBox.seal(_:) + 188 (Box.swift:38)
11  PromiseKit                    	0x00000001031dc9c0 partial apply + 24 (<compiler-generated>:0)
12  PromiseKit                    	0x00000001031e1c18 thunk for @escaping @callee_guaranteed (@in_guaranteed A) -> () + 20 (<compiler-generated>:0)
13  PromiseKit                    	0x00000001031dc42c partial apply for thunk for @escaping @callee_guaranteed (@in_guaranteed A) -> (@out ()) + 20 (<compiler-generated>:0)
14  PromiseKit                    	0x00000001031dc348 partial apply for closure #2 in EmptyBox.seal(_:) + 28 (Box.swift:51)
15  PromiseKit                    	0x00000001031dc3cc partial apply for thunk for @callee_guaranteed (@guaranteed @escaping @callee_guaranteed (@in_gua... + 104 (<compiler-generated>:0)
16  libswiftCore.dylib            	0x000000010468fc14 0x104684000 + 48148
17  PromiseKit                    	0x00000001031dafdc EmptyBox.seal(_:) + 388 (Box.swift:51)
18  PromiseKit                    	0x00000001031dc9c0 partial apply + 24 (<compiler-generated>:0)
19  PromiseKit                    	0x00000001031e1c18 thunk for @escaping @callee_guaranteed (@in_guaranteed A) -> () + 20 (<compiler-generated>:0)
20  PromiseKit                    	0x00000001031dc42c partial apply for thunk for @escaping @callee_guaranteed (@in_guaranteed A) -> (@out ()) + 20 (<compiler-generated>:0)
21  PromiseKit                    	0x00000001031dc348 partial apply for closure #2 in EmptyBox.seal(_:) + 28 (Box.swift:51)
22  PromiseKit                    	0x00000001031dc3cc partial apply for thunk for @callee_guaranteed (@guaranteed @escaping @callee_guaranteed (@in_gua... + 104 (<compiler-generated>:0)
23  libswiftCore.dylib            	0x000000010468fc14 0x104684000 + 48148
24  PromiseKit                    	0x00000001031dafdc EmptyBox.seal(_:) + 388 (Box.swift:51)
25  PromiseKit                    	0x00000001031dc9c0 partial apply + 24 (<compiler-generated>:0)
26  PromiseKit                    	0x00000001031e1c18 thunk for @escaping @callee_guaranteed (@in_guaranteed A) -> () + 20 (<compiler-generated>:0)
27  PromiseKit                    	0x00000001031dc42c partial apply for thunk for @escaping @callee_guaranteed (@in_guaranteed A) -> (@out ()) + 20 (<compiler-generated>:0)
28  PromiseKit                    	0x00000001031dc348 partial apply for closure #2 in EmptyBox.seal(_:) + 28 (Box.swift:51)
29  PromiseKit                    	0x00000001031dc3cc partial apply for thunk for @callee_guaranteed (@guaranteed @escaping @callee_guaranteed (@in_gua... + 104 (<compiler-generated>:0)
30  libswiftCore.dylib            	0x000000010468fc14 0x104684000 + 48148

EmptyBox.seal is repeated many times in the stack trace, so it is probably an infinite recursion. Unfortunately the stack tace in the crash log is not deep enough to include the original source. It might be an incorrect usahe of PromiseKit on our side, is there some pattern to look for? Or is it a PromiseKit bug that might have been already solved in a newer version? Thanks.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 13
  • Comments: 21 (9 by maintainers)

Most upvoted comments

Here’s a testcase, hope it helps 😃 Running on an iPhone XS Max iOS 13.4.1

import UIKit
import PromiseKit

class TestViewController: UIViewController {
    
    enum Example: Error {
        case Error
    }
    
    /*
     Common pattern used from the PromiseKit repo
     https://github.com/mxcl/PromiseKit/blob/master/Documentation/CommonPatterns.md#retry--polling
    */
    
    func attempt<T>(maximumRetryCount: Int = 3, delayBeforeRetry: DispatchTimeInterval = .seconds(2), _ body: @escaping () -> Promise<T>) -> Promise<T> {
        var attempts = 0
        func attempt() -> Promise<T> {
            attempts += 1
            print(attempts)
            return body().recover { error -> Promise<T> in
                guard attempts < maximumRetryCount else { print("Stopped"); throw error }
                return after(delayBeforeRetry).then(on: nil, attempt)
            }
        }
        return attempt()
    }
    
    private func exampleFunction() -> Promise<Void> {
        return Promise { seal in
            throw Example.Error
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        attempt(maximumRetryCount: 500, delayBeforeRetry: .milliseconds(1)) {
            self.exampleFunction()
        }.done { _ in
            print("DONE")
        }.catch { error in
            print("Error", error)
        }
    }
}