Fix the thread safe issue for accessing array with index, which may happend during incremental decoding

This commit is contained in:
DreamPiggy 2022-09-09 18:37:16 +08:00
parent 8a0c5e1ae0
commit 3775b895fb
1 changed files with 47 additions and 17 deletions

View File

@ -331,11 +331,10 @@ else OSSpinLockUnlock(&lock##_deprecated);
webpData.size = _imageData.length; webpData.size = _imageData.length;
WebPDemuxState state; WebPDemuxState state;
_demux = WebPDemuxPartial(&webpData, &state); _demux = WebPDemuxPartial(&webpData, &state);
SD_UNLOCK(_lock);
if (_demux && state != WEBP_DEMUX_PARSE_ERROR) { if (_demux && state != WEBP_DEMUX_PARSE_ERROR) {
[self scanAndCheckFramesValidWithDemuxer:_demux]; [self scanAndCheckFramesValidWithDemuxer:_demux];
} }
SD_UNLOCK(_lock);
} }
- (UIImage *)incrementalDecodedImageWithOptions:(SDImageCoderOptions *)options { - (UIImage *)incrementalDecodedImageWithOptions:(SDImageCoderOptions *)options {
@ -986,7 +985,6 @@ static float GetFloatValueForKey(NSDictionary * _Nonnull dictionary, NSString *
_hasAlpha = hasAlpha; _hasAlpha = hasAlpha;
_canvasWidth = canvasWidth; _canvasWidth = canvasWidth;
_canvasHeight = canvasHeight; _canvasHeight = canvasHeight;
_frameCount = frameCount;
_loopCount = loopCount; _loopCount = loopCount;
// If static WebP, does not need to parse the frame blend index // If static WebP, does not need to parse the frame blend index
@ -1032,8 +1030,10 @@ static float GetFloatValueForKey(NSDictionary * _Nonnull dictionary, NSString *
WebPDemuxReleaseIterator(&iter); WebPDemuxReleaseIterator(&iter);
if (frames.count != frameCount) { if (frames.count != frameCount) {
// frames not match, do not override current value
return NO; return NO;
} }
_frameCount = frameCount;
_frames = [frames copy]; _frames = [frames copy];
return YES; return YES;
@ -1052,27 +1052,57 @@ static float GetFloatValueForKey(NSDictionary * _Nonnull dictionary, NSString *
} }
- (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index { - (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index {
if (index >= _frameCount) { NSTimeInterval duration;
return 0; // Incremental Animation decoding may update frames when new bytes available
// Which should use lock to ensure frame count and frames match, ensure atomic logic
if (_idec != NULL) {
SD_LOCK(_lock);
if (index >= _frames.count) {
SD_UNLOCK(_lock);
return 0;
}
duration = _frames[index].duration;
SD_UNLOCK(_lock);
} else {
if (index >= _frames.count) {
return 0;
}
duration = _frames[index].duration;
} }
if (_frameCount <= 1) { return duration;
return 0;
}
return _frames[index].duration;
} }
- (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index { - (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index {
UIImage *image; UIImage *image;
if (index >= _frameCount) { // Incremental Animation decoding may update frames when new bytes available
return nil; // Which should use lock to ensure frame count and frames match, ensure atomic logic
} if (_idec != NULL) {
SD_LOCK(_lock); SD_LOCK(_lock);
if (_frameCount <= 1) { if (index >= _frames.count) {
image = [self safeStaticImageFrame]; SD_UNLOCK(_lock);
return nil;
}
if (_frames.count <= 1) {
image = [self safeStaticImageFrame];
} else {
image = [self safeAnimatedImageFrameAtIndex:index];
}
SD_UNLOCK(_lock);
} else { } else {
image = [self safeAnimatedImageFrameAtIndex:index]; // Animation Decoding need a lock on the canvas (which is shared), but the _frames is immutable and no lock needed
if (index >= _frames.count) {
return nil;
}
if (_frames.count <= 1) {
SD_LOCK(_lock);
image = [self safeStaticImageFrame];
SD_UNLOCK(_lock);
} else {
SD_LOCK(_lock);
image = [self safeAnimatedImageFrameAtIndex:index];
SD_UNLOCK(_lock);
}
} }
SD_UNLOCK(_lock);
return image; return image;
} }