← 输入框|github.com|刷新
Skip to content

OperatorFinally calls action twice if action throws exception. Exception thrown by action is swallowed #3435

Closed

Description

@artem-zinnatullin

While I was implementing #3434 I've found two problems with OperatorFinally.

I'll call OperatorFinally.action as finallyAction for better readability.

  1. If finallyAction is null — NullPointerException will be swallowed by SafeSubscriber, this can be solved via action != null check in the OperatorFinally (I'll make PR).
  2. If finallyAction throws exception, lift calls onError() and OperatorFinally invokes finallyAction again (this may brake user-defined logic)! And second exception is swallowed by the SafeSubscriber (see problem 1).

I vote for solving both of these problems before 1.0.15/1.1.10.

Activity

  1. artem-zinnatullin commented on Oct 10, 2015

    @artem-zinnatullin
    ContributorAuthor

    Here are the tests:

    @Test
    public void nullFinallyActionShouldBeCheckedASAP() {
        try {
            Observable
                    .just("value")
                    .finallyDo(null);
    
            fail();
        } catch (NullPointerException expected) {
    
        }
    }
    
    @Test
    public void ifFinallyActionThrowsExceptionShouldNotBeSwallowedAndActionShouldBeCalledOnce() {
        Action0 finallyAction = mock(Action0.class);
        doThrow(new IllegalStateException()).when(finallyAction).call();
    
        TestSubscriber<String> testSubscriber = new TestSubscriber<String>();
    
        Observable
                .just("value")
                .finallyDo(finallyAction)
                .subscribe(testSubscriber);
    
        testSubscriber.assertValue("value");
    
        verify(finallyAction).call();
        // Actual result:
        // Not only IllegalStateException was swallowed
        // But finallyAction was called twice!
    }
  2. artem-zinnatullin commented on Oct 10, 2015

    @artem-zinnatullin
    ContributorAuthor

    I'll try to send PRs with fixes ASAP, null check is easy, but second problem looks tricky.

  3. changed the title [-]OperatorFinally calls action twice if action throws exception and exception is swallowed[/-] [+]OperatorFinally calls action twice if action throws exception. Exception thrown by action is swallowed[/+] on Oct 10, 2015
  4. akarnokd commented on Oct 12, 2015

    @akarnokd
    Member

    If the action throws, you can't do much but call RxJavaPlugins.getInstance().getErrorHandler().handleError() for it.

  5. artem-zinnatullin commented on Oct 12, 2015

    @artem-zinnatullin
    ContributorAuthor

    We can throw it as Error. Leaving the app in an unknown state is very bad idea, especially in something like finallyDo().

  6. akarnokd commented on Oct 12, 2015

    @akarnokd
    Member

    The sequence has already terminated at that point and this operator is there to have side-effects after it. The exception has nowhere to go and there is no guarantee a thrown error reaches its intended target because of a potential async boundary. So it either propagates up to a synchronous caller, gets thrown away by the ExecutorService or gets sent to the error handler.

  7. akarnokd commented on Feb 9, 2016

    @akarnokd
    Member

    Can this be closed?

  8. artem-zinnatullin commented on Feb 9, 2016

    @artem-zinnatullin
    ContributorAuthor

    @akarnokd won't be able to work on this for at least 2 days, feel free to run the tests I posted ^ and see what we can do here or I'll investigate this in the end of the week.

    As far as I remember, the biggest problem is that action gets called twice if it throws exception and it may break app's logic in a dramatic manner.

  9. akarnokd commented on Apr 2, 2016

    @akarnokd
    Member

    Fix posted in #3823.

  10. akarnokd commented on Apr 14, 2016

    @akarnokd
    Member

    Closing via #3823

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions