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-7064] 4.1 Regression: Runtime crash when compiler optimises code from RxSwift library #49612

Closed
tcldr opened this issue Feb 22, 2018 · 10 comments
Assignees
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself optimized only Flag: An issue whose reproduction requires optimized compilation regression swift 4.1

Comments

@tcldr
Copy link

tcldr commented Feb 22, 2018

Previous ID SR-7064
Radar rdar://problem/37820485
Original Reporter @tcldr
Type Bug
Status Resolved
Resolution Done

Attachment: Download

Environment

Apple Swift version 4.1 (swiftlang-902.0.41 clang-902.0.31) – Xcode 9.3b3

Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug, 4.1Regression, OptimizedOnly
Assignee @eeckstein
Priority Medium

md5: d21e98eb0eac7f79557312a51c8fdd25

is duplicated by:

  • SR-7585 Possible compiler bug when passing method reference to function

Issue Description:

I've noticed a runtime crash when running fairly typical code with the popular RxSwift library.

It only occurs on optimised (Release) builds and therefore appears to be an issue with the Swift compiler's optimisation process.

I've included a small project which demonstrates the issue. From what I can tell it looks as though the optimiser may be stripping away a getter somewhere in shouldn't be.

Steps to reproduce:

  1. Open the 'BugWorkspace.xcworkspace' in Xcode 9.3b3

  2. Ensure the 'BugApp-Optimised' scheme is selected

  3. Run in the simulator (or device)

  4. Tap anywhere on the screen

  5. Crash

Backtrace:

* thread #​1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
    frame #​0: 0x000000010a593138 RxSwift`specialized TakeUntilSink._lock.getter(self=0x00006000000a94e0) at TakeUntil.swift:0 [opt]
    frame #​1: 0x000000010a59268b RxSwift`TakeUntilSink._lock.getter at TakeUntil.swift:0 [opt]
    frame #&#8203;2: 0x000000010a592d79 RxSwift`protocol witness for LockOwnerType._lock.getter in conformance TakeUntilSink<A, B> at TakeUntil.swift:0 [opt]
    frame #&#8203;3: 0x000000010a5bed6d RxSwift`merged (extension in RxSwift):RxSwift.LockOwnerType.lock() -> () + 13
    frame #&#8203;4: 0x000000010a5bed50 RxSwift`(extension in RxSwift):RxSwift.LockOwnerType.unlock() -> () + 16
    frame #&#8203;5: 0x000000010a5bee07 RxSwift`protocol witness for Lock.unlock() in conformance TakeUntilSink<A, B> at LockOwnerType.swift:0 [opt]
  * frame #&#8203;6: 0x000000010a5c1c16 RxSwift`SynchronizedOnType.synchronizedOn(_:) [inlined] $defer #&#8203;1 <A where A: RxSwift.SynchronizedOnType>(self=<unavailable>, self=0x00006000000a94e0) -> () in (extension in RxSwift):RxSwift.SynchronizedOnType.synchronizedOn(RxSwift.Event<A.E>) -> () at SynchronizedOnType.swift:15 [opt]
    frame #&#8203;7: 0x000000010a5c1c03 RxSwift`SynchronizedOnType.synchronizedOn(event=<unavailable>, self=0xbadd8bdf32d8bead) at SynchronizedOnType.swift:15 [opt]
    frame #&#8203;8: 0x000000010a592774 RxSwift`TakeUntilSink.on(event=<unavailable>, self=0x00006000000a94e0) at TakeUntil.swift:90 [opt]
    frame #&#8203;9: 0x000000010a592d90 RxSwift`protocol witness for ObserverType.on(_:) in conformance TakeUntilSink<A, B> at TakeUntil.swift:0 [opt]
    frame #&#8203;10: 0x000000010a5c74c2 RxSwift`Sink.forwardOn(event=<unavailable>, self=<unavailable>) at Sink.swift:35 [opt]
    frame #&#8203;11: 0x000000010a5bcdd1 RxSwift`AnonymousObservableSink.on(event=<unavailable>, self=0x000060000008d890) at Create.swift:50 [opt]
    frame #&#8203;12: 0x000000010a5bcf50 RxSwift`protocol witness for ObserverType.on(_:) in conformance AnonymousObservableSink<A> at Create.swift:0 [opt]
    frame #&#8203;13: 0x000000010a62a00a RxSwift`partial apply at ObserverType.swift:0 [opt]
    frame #&#8203;14: 0x000000010a598b1c RxSwift`AnyObserver.on(event=<unavailable>, self=<unavailable>) at AnyObserver.swift:39 [opt]
    frame #&#8203;15: 0x000000010a3cf4c4 RxCocoa`partial apply for closure #&#8203;1 in closure #&#8203;1 in Reactive<A>.controlEvent(_:) [inlined] function signature specialization <Arg[0] = Dead> of closure #&#8203;1 (observer=<unavailable>) -> () in closure #&#8203;1 (RxSwift.AnyObserver<()>) -> RxSwift.Disposable in (extension in RxCocoa):RxSwift.Reactive<A where A: __ObjC.UIControl>.controlEvent(__C.UIControlEvents) -> RxCocoa.ControlEvent<()> at UIControl+Rx.swift:44 [opt]
    frame #&#8203;16: 0x000000010a3cf4a4 RxCocoa`partial apply for closure #&#8203;1 in closure #&#8203;1 in Reactive<A>.controlEvent(_:) [inlined] closure #&#8203;1 (__ObjC.UIControl) -> () in closure #&#8203;1 (RxSwift.AnyObserver<()>) -> RxSwift.Disposable in (extension in RxCocoa):RxSwift.Reactive<A where A: __ObjC.UIControl>.controlEvent(__C.UIControlEvents) -> RxCocoa.ControlEvent<()> at UIControl+Rx.swift:42 [opt]
    frame #&#8203;17: 0x000000010a3cf4a4 RxCocoa`partial apply for closure #&#8203;1 in closure #&#8203;1 in Reactive<A>.controlEvent(_:) at UIControl+Rx.swift:0 [opt]
    frame #&#8203;18: 0x000000010a40f3a2 RxCocoa`@objc ControlTarget.eventHandler(_:) at ControlTarget.swift:73 [opt]
    frame #&#8203;19: 0x000000010a40f374 RxCocoa`@objc ControlTarget.eventHandler(_:) at ControlTarget.swift:71 [opt]
    frame #&#8203;20: 0x000000010b6e2d78 UIKit`-[UIApplication sendAction:to:from:forEvent:] + 83
    frame #&#8203;21: 0x000000010b85dd9c UIKit`-[UIControl sendAction:to:forEvent:] + 67
    frame #&#8203;22: 0x000000010b85e0b9 UIKit`-[UIControl _sendActionsForEvents:withEvent:] + 450
    frame #&#8203;23: 0x000000010b85d001 UIKit`-[UIControl touchesEnded:withEvent:] + 580
    frame #&#8203;24: 0x000000010b757a4f UIKit`-[UIWindow _sendTouchesForEvent:] + 2729
    frame #&#8203;25: 0x000000010b759151 UIKit`-[UIWindow sendEvent:] + 4086
    frame #&#8203;26: 0x000000010b6fcca0 UIKit`-[UIApplication sendEvent:] + 352
    frame #&#8203;27: 0x000000010c03d4bb UIKit`__dispatchPreprocessedEventFromEventQueue + 2796
    frame #&#8203;28: 0x000000010c0400d0 UIKit`__handleEventQueueInternal + 5949
    frame #&#8203;29: 0x000000010e2abe41 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
    frame #&#8203;30: 0x000000010e29073f CoreFoundation`__CFRunLoopDoSources0 + 271
    frame #&#8203;31: 0x000000010e28fcff CoreFoundation`__CFRunLoopRun + 1263
    frame #&#8203;32: 0x000000010e28f59b CoreFoundation`CFRunLoopRunSpecific + 635
    frame #&#8203;33: 0x0000000112a59a73 GraphicsServices`GSEventRunModal + 62
    frame #&#8203;34: 0x000000010b6e19e7 UIKit`UIApplicationMain + 159
    frame #&#8203;35: 0x000000010a0bbf40 BugApp`main at AppDelegate.swift:14 [opt]
    frame #&#8203;36: 0x000000010fe43955 libdyld.dylib`start + 1
    frame #&#8203;37: 0x000000010fe43955 libdyld.dylib`start + 1

View Controller to reproduce issue:

// ENSURE BUILD OPTIMISATION IS ENABLED

import UIKit
import RxSwift
import RxCocoa

class ViewController: UIViewController {

    let disposeBag = DisposeBag()

    override func loadView() {
        let button = UIButton(frame: .zero)
        button.backgroundColor = .red
        self.view = button
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        let button = view as! UIButton

        let reductionSubject = ReplaySubject <Void>.create(bufferSize: 1)
        let reducerStream = reductionSubject
            .flatMapLatest{ _ in button.rx.tap }
            .startWith(())
            .do(onNext: { print("state: \($0)") })

        reducerStream.subscribe(reductionSubject).disposed(by: disposeBag)
    }
}
@eeckstein
Copy link
Member

fixed in #14829

@swift-ci
Copy link
Collaborator

swift-ci commented Apr 5, 2018

Comment by Worth Baker (JIRA)

@eeckstein we're still seeing this regression (or a very similar issue) in the release versions of Xcode 9.3 / Swift 4.1. Note the following code snippet - tapping the button in the viewController is a 100% crasher when run with Swift release optimizations ( [-O] ) turned on:

import UIKit
import RxSwift

class ViewController: UIViewController {
    
    private let disposeBag = DisposeBag()
    
    private let publishSubject = PublishSubject<Void>()
    private let buttonPublishSubject = PublishSubject<Void>()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Add button
        let button = UIButton(type: .system)
        button.frame = view.bounds
        button.setTitle("I'll crash your app.", for: .normal)
        button.addTarget(self, action: #selector(buttonTapped(_:)), for: .touchUpInside)
        
        view.addSubview(button)
        
        // Setup observables
        buttonPublishSubject
            .subscribe(onNext: publishSubject.onNext) // ___CRASH___
//            .bind(to: publishSubject) // using `bind` avoids the crasher
//            .subscribe(onNext: { self.publishSubject.onNext($0) }) // also does not crash
            .disposed(by: disposeBag)
        
        publishSubject
            .observeOn(MainScheduler.instance)
            .subscribe(onNext: {
                print("button tapped")
            })
            .disposed(by: disposeBag)
    }

    @objc
    func buttonTapped(_ sender: Any) {
        self.buttonPublishSubject.onNext(())
    }
}

And here's the stack trace:

* thread #&#8203;1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0xc00000023a806ee8)
    frame #&#8203;0: 0x00000001047b240c RxSwift`PublishSubject.on(event=<unavailable>, self=0xc00000023a806ee8) at PublishSubject.swift:0 [opt]
    frame #&#8203;1: 0x00000001047b3630 RxSwift`protocol witness for ObserverType.on(_:) in conformance PublishSubject<A> at PublishSubject.swift:0 [opt]
  * frame #&#8203;2: 0x00000001047abcd8 RxSwift`ObserverType.onNext(element=() @ 0x000000016bc2d1c0, self=0xc00000023a806ee8) at ObserverType.swift:27 [opt]
    frame #&#8203;3: 0x00000001041d5c94 RxSwict_9.3_CrashTests`partial apply for ObserverType.onNext(_:) at ViewController.swift:0 [opt]
    frame #&#8203;4: 0x00000001047a89d4 RxSwift`closure #&#8203;2 in ObservableType.subscribe(event=, onNext=0x00000001041d5bf8 RxSwict_9.3_CrashTests`partial apply forwarder for (extension in RxSwift):RxSwift.ObserverType.onNext(A.E) -> () at ViewController.swift, onError=nil, disposable=<unavailable>, onCompleted=nil) at ObservableType+Extensions.swift:93 [opt]
    frame #&#8203;5: 0x00000001047a8c58 RxSwift`partial apply for closure #&#8203;2 in ObservableType.subscribe(onNext:onError:onCompleted:onDisposed:) at ObservableType+Extensions.swift:0 [opt]
    frame #&#8203;6: 0x0000000104757e20 RxSwift`AnonymousObserver.onCore(event=<unavailable>, self=<unavailable>) at AnonymousObserver.swift:24 [opt]
    frame #&#8203;7: 0x00000001047ab7fc RxSwift`ObserverBase.on(event=, self=0x00000001d405c9e0) at ObserverBase.swift:0 [opt]
    frame #&#8203;8: 0x00000001047aba58 RxSwift`protocol witness for ObserverType.on(_:) in conformance ObserverBase<A> at ObserverBase.swift:0 [opt]
    frame #&#8203;9: 0x00000001047abed0 RxSwift`partial apply at ObserverType.swift:0 [opt]
    frame #&#8203;10: 0x00000001047c8690 RxSwift`thunk for @escaping @callee_guaranteed (@in Event<A>) -> () at ShareReplayScope.swift:0 [opt]
    frame #&#8203;11: 0x00000001047b2564 RxSwift`PublishSubject.on(_:) [inlined] reabstraction thunk helper <A> from @escaping @callee_guaranteed (@in RxSwift.Event<A>) -> (@out ()) to @escaping @callee_guaranteed (@in RxSwift.Event<A>) -> () at PublishSubject.swift:0 [opt]
    frame #&#8203;12: 0x00000001047b255c RxSwift`PublishSubject.on(_:) [inlined] RxSwift.dispatch<A>(RxSwift.Bag<(RxSwift.Event<A>) -> ()>, RxSwift.Event<A>) -> () at Bag+Rx.swift:15 [opt]
    frame #&#8203;13: 0x00000001047b2548 RxSwift`PublishSubject.on(event=, self=<unavailable>) at PublishSubject.swift:64 [opt]
    frame #&#8203;14: 0x00000001047b3630 RxSwift`protocol witness for ObserverType.on(_:) in conformance PublishSubject<A> at PublishSubject.swift:0 [opt]
    frame #&#8203;15: 0x00000001047abcd8 RxSwift`ObserverType.onNext(element=() @ 0x000000010482a9c8, self=0x00000001d40d75a0) at ObserverType.swift:27 [opt]
    frame #&#8203;16: 0x00000001041d4f00 RxSwict_9.3_CrashTests`@objc ViewController.buttonTapped(_:) [inlined] RxSwict_9_3_CrashTests.ViewController.buttonTapped(sender=Any @ 0x000000016bc2d530, self=0x000000010552c000) -> () at ViewController.swift:48 [opt]
    frame #&#8203;17: 0x00000001041d4e88 RxSwict_9.3_CrashTests`@objc ViewController.buttonTapped(_:) at ViewController.swift:47 [opt]
    frame #&#8203;18: 0x000000018c1e1608 UIKit`-[UIApplication sendAction:to:from:forEvent:] + 96
    frame #&#8203;19: 0x000000018c1e1588 UIKit`-[UIControl sendAction:to:forEvent:] + 80
    frame #&#8203;20: 0x000000018c1cc2f0 UIKit`-[UIControl _sendActionsForEvents:withEvent:] + 440
    frame #&#8203;21: 0x000000018c1e0e7c UIKit`-[UIControl touchesEnded:withEvent:] + 576
    frame #&#8203;22: 0x000000018c1e099c UIKit`-[UIWindow _sendTouchesForEvent:] + 2544
    frame #&#8203;23: 0x000000018c1dbe6c UIKit`-[UIWindow sendEvent:] + 3208
    frame #&#8203;24: 0x000000018c1ad378 UIKit`-[UIApplication sendEvent:] + 340
    frame #&#8203;25: 0x000000018cafa85c UIKit`__dispatchPreprocessedEventFromEventQueue + 2364
    frame #&#8203;26: 0x000000018cafcde8 UIKit`__handleEventQueueInternal + 4760
    frame #&#8203;27: 0x000000018cafd150 UIKit`__handleEventQueueInternal + 5632
    frame #&#8203;28: 0x000000018caf5d04 UIKit`__handleHIDEventFetcherDrain + 152
    frame #&#8203;29: 0x0000000182d1e2e8 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 24
    frame #&#8203;30: 0x0000000182d1e268 CoreFoundation`__CFRunLoopDoSource0 + 88
    frame #&#8203;31: 0x0000000182d1daf0 CoreFoundation`__CFRunLoopDoSources0 + 204
    frame #&#8203;32: 0x0000000182d1b6c8 CoreFoundation`__CFRunLoopRun + 1048
    frame #&#8203;33: 0x0000000182c3bfb8 CoreFoundation`CFRunLoopRunSpecific + 436
    frame #&#8203;34: 0x0000000184ad3f84 GraphicsServices`GSEventRunModal + 100
    frame #&#8203;35: 0x000000018c2102e8 UIKit`UIApplicationMain + 208
    frame #&#8203;36: 0x00000001041d5398 RxSwict_9.3_CrashTests`main at AppDelegate.swift:12 [opt]
    frame #&#8203;37: 0x000000018275e56c libdyld.dylib`start + 4

We've confirmed that the crash does not occur when built with Xcode 9.2, nor when compiler optimizations are set to Debug ([-Onone]). Please advise if more information is needed or if a separate ticket should be opened. Thanks!

@swift-ci
Copy link
Collaborator

swift-ci commented Apr 6, 2018

Comment by Worth Baker (JIRA)

@eeckstein created a workspace that includes RxSwift and can reproduce the crash - decompress the ZIP, open the Xcode workspace, and build/run the "Crashing Scheme (Release)" scheme *on an iOS device (the crash will not occur in the iOS simulator). Thanks! RxSwift_Crash-Swift_4_1.zip

@eeckstein
Copy link
Member

worthbak (JIRA User) Thanks for reporting! We'll take a look

@eeckstein
Copy link
Member

Reproduced. This is most likely a different issue than the original one. Still investigating...

@eeckstein
Copy link
Member

Fixed on master with #15829

@swift-ci
Copy link
Collaborator

Comment by Worth Baker (JIRA)

Nice - thanks @eeckstein!

@swift-ci
Copy link
Collaborator

Comment by Romain (JIRA)

Hello @eeckstein, sorry to bother you.

Just reporting that this behaviour seems to still be reproductible with Xcode 9.3.1 - Apple Swift version 4.1 (swiftlang-902.0.48 clang-902.0.37.1). Well, I reproduced it with the RxSwift_Crash-Swift_4_1 archive linked above, if someone else can confirm this.

Thank you very much!

@eeckstein
Copy link
Member

Thanks for reporting!
Unfortunately this fix didn't make it into swiftlang-902.0.48.
It will be included in an upcoming release, starting with swiftlang-902.0.52.

@swift-ci
Copy link
Collaborator

Comment by Romain (JIRA)

All right thank you very much!

@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 optimized only Flag: An issue whose reproduction requires optimized compilation regression swift 4.1
Projects
None yet
Development

No branches or pull requests

4 participants