swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
67.58k stars 10.36k forks source link

[SR-11306] Unexpected crash by UIScrollView.publisher(for: \.contentOffset) #53707

Open swift-ci opened 5 years ago

swift-ci commented 5 years ago
Previous ID SR-11306
Radar rdar://54318302
Original Reporter disho (JIRA User)
Type Bug
Additional Detail from JIRA | | | |------------------|-----------------| |Votes | 0 | |Component/s | | |Labels | Bug | |Assignee | bendjones (JIRA) | |Priority | Medium | md5: 47ec293034be223e8941121bc333f3a8

Issue Description:

Hello 🙂,

I am creating a custom Combine publisher by extending UIScrollView, as the following.

extension UIScrollView {
    var contentOffsetPublisher: AnyPublisher<CGPoint, Never> {
        return self.publisher(for: \.contentOffset)
            .eraseToAnyPublisher()
    }
}

However, I just realised that when contentOffsetPublisher is used, the app crashes with the following information.

libsystem_platform.dylib`_os_unfair_lock_recursive_abort:
 0x7fff51355425 <+0>: movl %edi, %eax
 0x7fff51355427 <+2>: leaq 0x7ae(%rip), %rcx ; "BUG IN CLIENT OF LIBPLATFORM: Trying to recursively lock an os_unfair_lock"
 0x7fff5135542e <+9>: movq %rcx, 0x3879a02b(%rip) ; gCRAnnotations + 8
 0x7fff51355435 <+16>: movq %rax, 0x3879a054(%rip) ; gCRAnnotations + 56
-> 0x7fff5135543c <+23>: ud2 

This is something that I don't expect to happen. However, let me know if I am missing something.

(Fyi, there is no crash when I debounce it)

Thank you in advance.

harlanhaskins commented 5 years ago

This sounds like it's an issue with the Combine framework, which is not part of the Swift open source project, so it's going to be tracked on https://feedbackassistant.apple.com.

Can you submit feedback on that website and attach a sample project that's crashing? That would really help the Combine folks figure out the root cause of your issue. Thanks!

swift-ci commented 5 years ago

Comment by Ben D. Jones (JIRA)

I'll take a look I'm one of the maintainers of Combine...

swift-ci commented 5 years ago

Comment by Ben D. Jones (JIRA)

@swift-ci create

swift-ci commented 5 years ago

Comment by Ben D. Jones (JIRA)

I've filed a radar internally for this... thanks for the report!

swift-ci commented 5 years ago

Comment by Ben D. Jones (JIRA)

So apologies for this taking a bit to respond to but the following is working for me in Xcode Beta 7 (11M392r)

Here's what I used to test this out.

import UIKit
import Combine

class ViewController: UIViewController {

    var subscriptions: [AnyCancellable] = []
    let scrollView = UIScrollView()

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.

        view.addSubview(scrollView)
        scrollView.frame = view.frame
        scrollView.contentSize = CGSize(width: view.frame.width, height: view.frame.height * 2)

        scrollView.contentOffsetPublisher.sink {
            print("Offset: \($0)")
        }
        .store(in: &subscriptions)
    }

}

extension UIScrollView {
    var contentOffsetPublisher: AnyPublisher<CGPoint, Never> {
        return self.publisher(for: \.contentOffset)
            .eraseToAnyPublisher()
    }
}

Running this and scrolling I'm getting the signals in the sink as expected.

Offset: (0.0, -44.0)
Offset: (0.0, -44.0)
Offset: (0.0, -44.0)
Offset: (0.0, -30.0)
Offset: (0.0, -27.5)
Offset: (0.0, -27.5)
Offset: (0.0, -13.0)
Offset: (0.0, 34.0)
Offset: (0.0, 34.0)
Offset: (0.0, 90.5)
Offset: (0.0, 173.0)
Offset: (0.0, 173.0)
Offset: (0.0, 272.5)
Offset: (0.0, 388.0)
Offset: (0.0, 388.0)
Offset: (0.0, 434.0)

This is a simple example but mind re-testing this and letting me know what you see.