Skip to content

[SR-7064] 4.1 Regression: Runtime crash when compiler optimises code from RxSwift library #49612

@tcldr

Description

@tcldr
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)
    }
}

Metadata

Metadata

Assignees

Labels

bugA deviation from expected or documented behavior. Also: expected but undesirable behavior.compilerThe Swift compiler itselfoptimized onlyFlag: An issue whose reproduction requires optimized compilationregressionswift 4.1

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions