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

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

Closed
artem-zinnatullin opened this issue Oct 10, 2015 · 9 comments
Labels

Comments

@artem-zinnatullin
Copy link
Contributor

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 nullNullPointerException 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.

@artem-zinnatullin
Copy link
Contributor Author

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!
}

@artem-zinnatullin
Copy link
Contributor Author

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

@artem-zinnatullin artem-zinnatullin 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 Oct 10, 2015
@akarnokd
Copy link
Member

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

@akarnokd akarnokd added the Bug label Oct 12, 2015
@artem-zinnatullin
Copy link
Contributor Author

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

@akarnokd
Copy link
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.

@akarnokd
Copy link
Member

akarnokd commented Feb 9, 2016

Can this be closed?

@artem-zinnatullin
Copy link
Contributor Author

@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.

@akarnokd
Copy link
Member

akarnokd commented Apr 2, 2016

Fix posted in #3823.

@akarnokd
Copy link
Member

Closing via #3823

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants