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

DecodeJob.cancel may be racing with DecodeJob.decodeSource #424

Closed
TWiStErRob opened this issue Apr 18, 2015 · 1 comment
Closed

DecodeJob.cancel may be racing with DecodeJob.decodeSource #424

TWiStErRob opened this issue Apr 18, 2015 · 1 comment
Labels
Milestone

Comments

@TWiStErRob
Copy link
Collaborator

Glide Version/Integration library (if any): 3.5.2/3.6.0-SNAPSHOT
Issue details/Repro steps: found this while researching a response:

class DecodeJob {
    public void cancel() {
2       fetcher.cancel();
5       isCancelled = true; // -------------------------------
    }                                                        |
    private Resource<T> decodeSource() throws Exception {    |
        Resource<T> decoded = null;                          |
        try {                                                |
1           final A data = fetcher.loadData(priority);       |
3           if (isCancelled) { // <---------------------------
                return null;
            }
4           decoded = decodeFromSourceData(data);
        } finally {
            fetcher.cleanup();
        }
        return decoded;
    }

I think cancel's lines should be the other way around. Think about a case where:

  1. loadData connects to remote endpoint (let's call this conn).
  2. DataFetcher implements cancel properly, i.e.interrupts the connection being initiated in conn.
    The interruption throws an exception from conn which is then caught inside loadData.
  3. Which then results in an immediate return x. Now we're back in decodeSource data having the value x and isCancelled may not yet be set to true, because who knows how fast fetcher.cancel() returns (it's another thread I couldn't see any sync around here).
  4. This in the end leads to data/x being handed to decodeFromSourceData. Once data/x escapes the scope of decodeSource it will be handed to sourceDecoder or cacheEncoder and the whole lifecycle will follow through even though
  5. isCancelled should have been true before decodeFromSourceData is called. Also data/x may be corrupted because of interruption.

EngineRunnable will however catch this and just plain recycle our hard-en/de-coded resource because isCancelled is set first in its cancel.
The above may be intentional though to fill the cache (even if the request can cleared), but it looks to me it only works if cancel is not implemented.

@sjudd
Copy link
Collaborator

sjudd commented Apr 19, 2015

Yup looks like this is an issue, we should set isCancelled before calling fetcher.cancel(). Nice catch!

@sjudd sjudd added the bug label Apr 19, 2015
@sjudd sjudd added this to the 3.6.0 milestone Apr 19, 2015
@sjudd sjudd closed this as completed in ad9c91c Apr 20, 2015
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