url is kind of NSString and shouldUseWeakMemoryCache is YES, APP will crash. (#3686)

* NSString will crash

* unit test

* unit test opt

---------

Co-authored-by: songjk <fusheng@douyu.tv>
This commit is contained in:
aasdsjk 2024-03-14 15:20:11 +08:00 committed by GitHub
parent db1efed37e
commit 98d058a1ea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 58 additions and 0 deletions

View File

@ -61,6 +61,18 @@ const int64_t SDWebImageProgressUnitCountUnknown = 1LL;
setImageBlock:(nullable SDSetImageBlock)setImageBlock
progress:(nullable SDImageLoaderProgressBlock)progressBlock
completed:(nullable SDInternalCompletionBlock)completedBlock {
// Very common mistake is to send the URL using NSString object instead of NSURL. For some strange reason, Xcode won't
// throw any warning for this type mismatch. Here we failsafe this error by allowing URLs to be passed as NSString.
// if url is NSString and shouldUseWeakMemoryCache is true, [cacheKeyForURL:context] will crash. just for a global protect.
if ([url isKindOfClass:NSString.class]) {
url = [NSURL URLWithString:(NSString *)url];
}
// Prevents app crashing on argument type error like sending NSNull instead of NSURL
if (![url isKindOfClass:NSURL.class]) {
url = nil;
}
if (context) {
// copy to avoid mutable object
context = [context copy];

View File

@ -620,6 +620,52 @@
[self waitForExpectationsWithCommonTimeout];
}
// test url is nil
- (void)testUIViewImageUrlForNilWorks {
XCTestExpectation *expectation = [self expectationWithDescription:@"Completion is called with url is nil"];
UIImageView *imageView = [[UIImageView alloc] init];
SDImageCache *cache = [[SDImageCache alloc] initWithNamespace:@"Test"];
cache.config.shouldUseWeakMemoryCache = YES;
SDWebImageManager *imageManager = [[SDWebImageManager alloc] initWithCache:cache loader:[SDWebImageDownloader sharedDownloader]];
[imageView sd_setImageWithURL:nil placeholderImage:nil options:0 context:@{SDWebImageContextCustomManager:imageManager} progress:nil completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
expect(image).to.beNil();
[expectation fulfill];
}];
[self waitForExpectationsWithCommonTimeout];
}
// test url is NSString.
- (void)testUIViewImageUrlForStringWorks {
XCTestExpectation *expectation = [self expectationWithDescription:@"Completion is called with url is NSString"];
UIImageView *imageView = [[UIImageView alloc] init];
SDImageCache *cache = [[SDImageCache alloc] initWithNamespace:@"Test"];
cache.config.shouldUseWeakMemoryCache = YES;
SDWebImageManager *imageManager = [[SDWebImageManager alloc] initWithCache:cache loader:[SDWebImageDownloader sharedDownloader]];
[imageView sd_setImageWithURL:kTestJPEGURL placeholderImage:nil options:0 context:@{SDWebImageContextCustomManager:imageManager} progress:nil completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
expect(image).notTo.beNil();
[expectation fulfill];
}];
[self waitForExpectationsWithCommonTimeout];
}
// test url is NSURL
- (void)testUIViewImageUrlForNSURLWorks {
XCTestExpectation *expectation = [self expectationWithDescription:@"Completion is called with url is NSURL"];
UIImageView *imageView = [[UIImageView alloc] init];
SDImageCache *cache = [[SDImageCache alloc] initWithNamespace:@"Test"];
cache.config.shouldUseWeakMemoryCache = YES;
SDWebImageManager *imageManager = [[SDWebImageManager alloc] initWithCache:cache loader:[SDWebImageDownloader sharedDownloader]];
[imageView sd_setImageWithURL:[NSURL URLWithString:kTestJPEGURL] placeholderImage:nil options:0 context:@{SDWebImageContextCustomManager:imageManager} progress:nil completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
expect(image).notTo.beNil();
[expectation fulfill];
}];
[self waitForExpectationsWithCommonTimeout];
}
#pragma mark - Helper
- (NSString *)testJPEGPath {