Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-1006] [unowned self] captures randomly crash at closure creation time #43618

Closed
swift-ci opened this issue Mar 21, 2016 · 10 comments
Closed
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself

Comments

@swift-ci
Copy link
Collaborator

Previous ID SR-1006
Radar rdar://problem/25830114
Original Reporter marc (JIRA User)
Type Bug
Status Closed
Resolution Done

Attachment: Download

Environment

iOS devices & simulators, various iOS versions, Swift 2.1.1 (from Xcode 7.2.1), debug & release builds

Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug
Assignee None
Priority Medium

md5: c1ac9e9172cdf0eb0f3a6278028d0b48

Issue Description:

Code like the following randomly crashes at runtime:

button.tapped = { [unowned self] in
    self.buttonTapped()
}

The crash happens at the time the closure is created and assigned to the variable. It does not happen at the time the closure is actually called.

That code is called during the initialization of the object referenced by self so it's definitely still alive.

@belkadan
Copy link
Contributor

Can you attach a self-contained reproducing project or playground?

@swift-ci
Copy link
Collaborator Author

Comment by Marc Knaup (JIRA)

Unfortunately we were not yet able to create an isolated test project which causes that crash.

We can only reproduce the crash in our app (with quite a big codebase) by scrolling around like a monkey.
Although we have no evidence yet we believe that the crash is caused by a multi-threading race condition. In our app other threads are quite active while the crash is happening. iOS for example is doing a lot of AVPlayer voodoo in the background.

We'll try again to create an isolated test project with Xcode 7.3.

@DevAndArtist
Copy link
Mannequin

DevAndArtist mannequin commented Mar 28, 2016

Could this Stackoverflow post could be somehow related and could be used to reproduce the bug?
http://stackoverflow.com/q/36231069/4572536

@swift-ci
Copy link
Collaborator Author

Comment by Antti Laitala (JIRA)

This is happening in our large Swift project also. The result of this is that we have had to ban the usage of [unowned] captures entirely.

I would argue that this is a pretty severe issue with [unowned] captures being a fundamental part of the language design.

I'm glad we found this crash before releasing the software to our clients.

I doubt that this has anything to do with threading, since all of our [unowned] captures were done in the main thread.

@swift-ci
Copy link
Collaborator Author

Comment by Antti Laitala (JIRA)

This bug is still present with Xcode 7.3.1 GM and iOS 9.3.

@swift-ci
Copy link
Collaborator Author

swift-ci commented May 2, 2016

Comment by Antti Laitala (JIRA)

Is there any progress on this, since this does render one language feature complete unusable? I've had to ban the usage of [unowned] captures in my other project now as well. It does seem that the likelihood of these [unowned] capture crashes at creation time goes up the more you have them.

@swift-ci
Copy link
Collaborator Author

Comment by Eric Ito (JIRA)

I have a reproducible case – however I can't seem to reproduce this in Swift 2.2

import Foundation

protocol Device {
    var locationHandler: ((location: Any?, error: NSError?) -> Void)? {get set}
}

class InternalDevice: NSObject, Device {
    var locationHandler: ((location: Any?, error: NSError?) -> Void)?
}

class ExternalDevice: NSObject, Device {
    var locationHandler: ((location: Any?, error: NSError?) -> Void)?
}

class DeviceSource: NSObject {
    
    var device: Device
    private let name = "Device Data Source"
    
    deinit {
        print("[DEINIT] device source")
    }
    
    init(device d: Device) {
        device = d
        super.init()
        
        print("Creating a new DeviceSource")
        
        device.locationHandler = { [unowned self] (location: Any?, error: NSError?) in
            print(self.name)
        }
    }
}

let id = InternalDevice()
let ed = ExternalDevice()

var source = DeviceSource(device: id)

while true {
    if source.device is InternalDevice {
        source = DeviceSource(device: ed)
    } else {
        source = DeviceSource(device: id)
    }
    NSThread.sleepForTimeInterval(1.0)
}

@swift-ci
Copy link
Collaborator Author

Comment by Eric Ito (JIRA)

you can run the above code in a playground to reproduce the crash...
if i nil out locationHandler in the deinit, the crash is no longer reproducible at Swift 2.1

@swift-ci
Copy link
Collaborator Author

Comment by Marc Knaup (JIRA)

I've just checked our app's crash logs and we also haven't experienced this issue anymore for several months now.
I'll mark it as resolved 🙂

@swift-ci
Copy link
Collaborator Author

Comment by Marc Knaup (JIRA)

The issue is no longer present in Swift 2.3.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself
Projects
None yet
Development

No branches or pull requests

2 participants