Skip to content

Commit 7ff561a

Browse files
committed
Using try-catch for CoreSVG vector image before rendering on screen, protect some crash for user
However, this can only solve some of crashes, some of crashes like Danger Pointer are un-catchable
1 parent afbe025 commit 7ff561a

File tree

2 files changed

+37
-7
lines changed

2 files changed

+37
-7
lines changed

Example/SDWebImageSVGCoder/SDViewController.m

+5
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ - (void)viewDidLoad
2525
NSURL *svgURL = [NSURL URLWithString:@"https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/w3c.svg"];
2626
NSURL *svgURL2 = [NSURL URLWithString:@"https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/wikimedia.svg"];
2727
NSURL *svgURL3 = [NSURL URLWithString:@"https://simpleicons.org/icons/github.svg"];
28+
// Some SVG will fail, this demo check them and the C++/Objc exception should be catched by SDK
29+
NSURL *badSVGURL = [NSURL URLWithString:@"https://openseauserdata.com/files/b809fe0925eb3629bb1d3edb1fafcc88.svg"];
30+
[SDWebImageManager.sharedManager loadImageWithURL:badSVGURL options:0 progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
31+
32+
}];
2833

2934
CGSize screenSize = self.view.bounds.size;
3035

SDWebImageSVGCoder/Classes/SDImageSVGCoder.m

+32-7
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,12 @@ + (SDImageSVGCoder *)sharedCoder {
4949
}
5050

5151
+ (void)initialize {
52-
SDCGSVGDocumentRetain = dlsym(RTLD_DEFAULT, SDBase64DecodedString(@"Q0dTVkdEb2N1bWVudFJldGFpbg==").UTF8String);
53-
SDCGSVGDocumentRelease = dlsym(RTLD_DEFAULT, SDBase64DecodedString(@"Q0dTVkdEb2N1bWVudFJlbGVhc2U=").UTF8String);
54-
SDCGSVGDocumentCreateFromData = dlsym(RTLD_DEFAULT, SDBase64DecodedString(@"Q0dTVkdEb2N1bWVudENyZWF0ZUZyb21EYXRh").UTF8String);
55-
SDCGSVGDocumentWriteToData = dlsym(RTLD_DEFAULT, SDBase64DecodedString(@"Q0dTVkdEb2N1bWVudFdyaXRlVG9EYXRh").UTF8String);
56-
SDCGContextDrawSVGDocument = dlsym(RTLD_DEFAULT, SDBase64DecodedString(@"Q0dDb250ZXh0RHJhd1NWR0RvY3VtZW50").UTF8String);
57-
SDCGSVGDocumentGetCanvasSize = dlsym(RTLD_DEFAULT, SDBase64DecodedString(@"Q0dTVkdEb2N1bWVudEdldENhbnZhc1NpemU=").UTF8String);
52+
SDCGSVGDocumentRetain = (CGSVGDocumentRef (*)(CGSVGDocumentRef))dlsym(RTLD_DEFAULT, SDBase64DecodedString(@"Q0dTVkdEb2N1bWVudFJldGFpbg==").UTF8String);
53+
SDCGSVGDocumentRelease = (void (*)(CGSVGDocumentRef))dlsym(RTLD_DEFAULT, SDBase64DecodedString(@"Q0dTVkdEb2N1bWVudFJlbGVhc2U=").UTF8String);
54+
SDCGSVGDocumentCreateFromData = (CGSVGDocumentRef (*)(CFDataRef data, CFDictionaryRef options))dlsym(RTLD_DEFAULT, SDBase64DecodedString(@"Q0dTVkdEb2N1bWVudENyZWF0ZUZyb21EYXRh").UTF8String);
55+
SDCGSVGDocumentWriteToData = (void (*)(CGSVGDocumentRef document, CFDataRef data, CFDictionaryRef options))dlsym(RTLD_DEFAULT, SDBase64DecodedString(@"Q0dTVkdEb2N1bWVudFdyaXRlVG9EYXRh").UTF8String);
56+
SDCGContextDrawSVGDocument = (void (*)(CGContextRef context, CGSVGDocumentRef document))dlsym(RTLD_DEFAULT, SDBase64DecodedString(@"Q0dDb250ZXh0RHJhd1NWR0RvY3VtZW50").UTF8String);
57+
SDCGSVGDocumentGetCanvasSize = (CGSize (*)(CGSVGDocumentRef document))dlsym(RTLD_DEFAULT, SDBase64DecodedString(@"Q0dTVkdEb2N1bWVudEdldENhbnZhc1NpemU=").UTF8String);
5858
#if SD_UIKIT || SD_WATCH
5959
SDImageWithCGSVGDocumentSEL = NSSelectorFromString(SDBase64DecodedString(@"X2ltYWdlV2l0aENHU1ZHRG9jdW1lbnQ6"));
6060
SDCGSVGDocumentSEL = NSSelectorFromString(SDBase64DecodedString(@"X0NHU1ZHRG9jdW1lbnQ="));
@@ -152,7 +152,15 @@ - (NSData *)encodedDataWithImage:(UIImage *)image format:(SDImageFormat)format o
152152
return nil;
153153
}
154154

155-
SDCGSVGDocumentWriteToData(document, (__bridge CFDataRef)data, NULL);
155+
@try {
156+
// WARNING! Some CoreSVG exceptions can be catched, but not always
157+
// If you finally crash here (un-catchable), you can only workaround (or hope Apple fix this)
158+
// Do not encode vector UIImage into NSData, query `SDImageCache` for the same key and get back SVG Data
159+
SDCGSVGDocumentWriteToData(document, (__bridge CFMutableDataRef)data, NULL);
160+
} @catch (...) {
161+
// CoreSVG export failed
162+
return nil;
163+
}
156164

157165
return [data copy];
158166
}
@@ -178,6 +186,23 @@ - (UIImage *)createVectorSVGWithData:(nonnull NSData *)data {
178186
image = ((UIImage *(*)(id,SEL,CGSVGDocumentRef))[UIImage.class methodForSelector:SDImageWithCGSVGDocumentSEL])(UIImage.class, SDImageWithCGSVGDocumentSEL, document);
179187
SDCGSVGDocumentRelease(document);
180188
#endif
189+
190+
// CoreSVG has compatible for some SVG/1.1 format (like Font issue) and may crash when rendering on screen (not here, Core Animation commit time)
191+
// So, we snapshot a 1x1 pixel image and try catch here to check :(
192+
193+
SDGraphicsImageRenderer *renderer = [[SDGraphicsImageRenderer alloc] initWithSize:CGSizeMake(1, 1)];
194+
@try {
195+
__unused UIImage *dummyImage = [renderer imageWithActions:^(CGContextRef _Nonnull context) {
196+
// WARNING! Some CoreSVG exceptions can be catched, but not always
197+
// If you finally crash here (un-catchable), you can only workaround (or hope Apple fix this)
198+
// Change your code to use `SDWebImageContextImageThumbnailPixelSize` context option with enough size to render bitmap SVG instead
199+
[image drawInRect:CGRectMake(0, 0, 1, 1)];
200+
}];
201+
} @catch (...) {
202+
// CoreSVG decode failed
203+
return nil;
204+
}
205+
181206
return image;
182207
}
183208

0 commit comments

Comments
 (0)