iOS: Fix an image loader crash
Summary: Fixes #10433 The code didn't account for the fact that cancelLoad is set by two different threads. It gets set on the URL request queue when the request completes successfully and it gets set on the UI queue during cancelation. This oversight lead to a couple of different kinds of crashes. 1. Attempt to invoke a nil function -- We check that cancelLoad is non-nil and on the next line we call it. However, cancelLoad could have been set to nil by the other thread between the time it was verified to be non-nil and the time it was called. Consequently, the program will attempt to call nil and crash. 2. Block deallocated while it's executing -- Suppose cancelLoad points to a block, it is verified to be non-nil, and it is successfully invoked. In the middle of executing the block, cancelLoad, the last reference to the block, is set to nil. This causes the block to be deallocated and its captured values to be freed. However, the block continues executing and the next time it attempts to use a captured value Closes https://github.com/facebook/react-native/pull/11145 Differential Revision: D4261499 Pulled By: javache fbshipit-source-id: 46424c6dd8cfa085cef32d945308de07798040bc
This commit is contained in:
parent
964635848b
commit
23423774ba
|
@ -381,9 +381,10 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image,
|
||||||
});
|
});
|
||||||
|
|
||||||
return ^{
|
return ^{
|
||||||
if (cancelLoad && !cancelled) {
|
dispatch_block_t cancelLoadLocal = cancelLoad;
|
||||||
cancelLoad();
|
cancelLoad = nil;
|
||||||
cancelLoad = nil;
|
if (cancelLoadLocal && !cancelled) {
|
||||||
|
cancelLoadLocal();
|
||||||
}
|
}
|
||||||
OSAtomicOr32Barrier(1, &cancelled);
|
OSAtomicOr32Barrier(1, &cancelled);
|
||||||
};
|
};
|
||||||
|
@ -515,8 +516,9 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image,
|
||||||
__block volatile uint32_t cancelled = 0;
|
__block volatile uint32_t cancelled = 0;
|
||||||
__block dispatch_block_t cancelLoad = nil;
|
__block dispatch_block_t cancelLoad = nil;
|
||||||
dispatch_block_t cancellationBlock = ^{
|
dispatch_block_t cancellationBlock = ^{
|
||||||
if (cancelLoad && !cancelled) {
|
dispatch_block_t cancelLoadLocal = cancelLoad;
|
||||||
cancelLoad();
|
if (cancelLoadLocal && !cancelled) {
|
||||||
|
cancelLoadLocal();
|
||||||
}
|
}
|
||||||
OSAtomicOr32Barrier(1, &cancelled);
|
OSAtomicOr32Barrier(1, &cancelled);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue