ReactiveX / RxSwift

Reactive Programming in Swift

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Value leaks its continuation

kjaklinovic opened this issue · comments

Short description of the issue:

Example code will produce a console output: SWIFT TASK CONTINUATION MISUSE: value leaked its continuation!

Expected outcome:

I would expect no console output indicating issues with continuation.

What actually happens:

If you look at the example you will notice that the error triggers the dispose block in doSomething1 and the task is canceled. If you look at the code for the value computed property you can notice that onCancel will call dispose function which will dispose the subscription that never got success or error event. Because of that resume was never called for the continuation which results in the console output described above.

  var value: Element {
      get async throws {
          let disposable = SingleAssignmentDisposable()
          return try await withTaskCancellationHandler(
              operation: {
                  try await withCheckedThrowingContinuation { continuation in
                      disposable.setDisposable(
                          self.subscribe(
                              onSuccess: { continuation.resume(returning: $0) },
                              onFailure: { continuation.resume(throwing: $0) }
                          )
                      )
                  }
              },
              onCancel: { [disposable] in
                  disposable.dispose()
              }
          )
      }
  }

Self contained code example that reproduces the issue:

_ = Observable<Int>.interval(
    .seconds(1),
    scheduler: MainScheduler.instance
)
    .enumerated()
    .do { if $0.index > 0 { throw SomeError.error } }
    .map { _ in () }
    .flatMap(doSomething1)
    .subscribe()

func doSomething1() -> Single<Void> {
    Single.create { single in
        let task = Task {
            do { single(.success(try await doSomething2())) }
            catch { single(.failure(error)) }
        }

        return Disposables.create { task.cancel() }
    }
}

func doSomething2() async throws {
    try await doSomething3().value
}

func doSomething3() -> Single<Void> {
    Single
        .just(())
        .delay(.seconds(5), scheduler: MainScheduler.instance)
}

Platform/Environment

  • iOS
  • macOS
  • tvOS
  • watchOS
  • playgrounds

How easy is to reproduce? (chances of successful reproduce after running the self contained code)

  • easy, 100% repro
  • sometimes, 10%-100%
  • hard, 2% - 10%
  • extremely hard, %0 - 2%

Xcode version:

  13.4

Installation method:

  • CocoaPods
  • Carthage
  • Git submodules

I have multiple versions of Xcode installed:
(so we can know if this is a potential cause of your issue)

  • yes (which ones)
  • no

Level of RxSwift knowledge:
(this is so we can understand your level of knowledge
and formulate the response in an appropriate manner)

  • just starting
  • I have a small code base
  • I have a significant code base

Fixed in #2427. Will be released in the upcoming version.
Thanks!

thank you @kjaklinovic for this report, I had exactly the same issue.

@freak4pc This one has been fixed for quite some time now, but there has been no new release since then. What's the current timeline for the next release?

Sorry about that, I'll try to take care of it over the weekend

Awesome, thank you, Shai!

@freak4pc 🥺 👉 👈

Sorry, I'm moving to a new apartment today and it's been quite hectic these past few weeks. I'll do my best to take care of it in the following days. Apologies for the delay.,

No worries! Life is more important than work :) Thanks for all the effort you put into this!

commented

@freak4pc ... any updates on release schedule? sorry to nag :)