对于某些JPG图像,CFRelease()的间歇性崩溃调用NULL

时间:2017-08-29 14:49:29

标签: ios objective-c crash jpeg cgimagesource

在我的iOS应用中,我从s3下载游戏资产。我的艺术家更新了其中一个资产,我们立即开始看到新资产崩溃了。

以下是处理它们的代码:

+ (UIImage *)imageAtPath:(NSString *)imagePath scaledToSize:(CGSize)size
{
    // Create the image source (from path)
    CGImageSourceRef imageSource = CGImageSourceCreateWithURL((__bridge CFURLRef) [NSURL fileURLWithPath:imagePath], NULL);
    NSParameterAssert(imageSource);

    // Get the image dimensions (without loading the image into memory)
    CGFloat width = 512.0f, height = 384.0f;
    CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, NULL);
    NSParameterAssert(imageProperties);

    if (imageProperties) {

        CFNumberRef widthNumRef  = CFDictionaryGetValue(imageProperties, kCGImagePropertyPixelWidth);
        if (widthNumRef != NULL) {
            CFNumberGetValue(widthNumRef, kCFNumberCGFloatType, &width);
        }

        CFNumberRef heightNumRef = CFDictionaryGetValue(imageProperties, kCGImagePropertyPixelHeight);
        if (heightNumRef != NULL) {
            CFNumberGetValue(heightNumRef, kCFNumberCGFloatType, &height);
        }
         CFRelease(imageProperties);

    } else {

        // If the image info is somehow missing, make up some numbers so we don't divide by zero
        width = 512;
        height = 384;
    }

    // Create thumbnail options
    CGFloat maxDimension = size.height;

    if (useDeviceNativeScale) {
        maxDimension *= [UIScreen mainScreen].scale;
    }
    NSParameterAssert(maxDimension);

    // If we have a really wide image, scaling it to the screen height will make it too blurry.
    // Here we calculate the maximum dimension we want (probably width) to make the image be the full height of the device
    CGFloat imageAspectRatio = width / height;

    if (width > height) {
        maxDimension *= imageAspectRatio;
    }

    CFDictionaryRef options = (__bridge CFDictionaryRef) @{
                                                       (id) kCGImageSourceCreateThumbnailWithTransform : @YES,
                                                       (id) kCGImageSourceCreateThumbnailFromImageAlways : @YES,
                                                       (id) kCGImageSourceShouldCache : @YES,
                                                       (id) kCGImageSourceThumbnailMaxPixelSize : @(maxDimension)
                                                       };
    // Generate the thumbnail
    CGImageRef thumbnail = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options); 
    CFRelease(imageSource);
    //  Crashlytics says the crash is on this line, even though the line above is the one that uses `CFRelease()`
    UIImage *image = [UIImage imageWithCGImage:thumbnail];
    CGImageRelease(thumbnail); 
    NSAssert(image.size.height - SCREEN_MIN_LENGTH * [UIScreen mainScreen].scale < 1, @"Image should be the height of the view");

    return image;
}

这是Fabric的Crashlytics的堆栈跟踪:

  

0。崩溃:com.apple.main-thread

     

0 CoreFoundation 0x1820072a0 CFRelease + 120

     

1 Homer 0x10014e7f0 + [UIImage(ResizeBeforeLoading)imageAtPath:scaledToSize:](UIImage + ResizeBeforeLoading.m:98)

使用此崩溃信息键:

  

CRASH_INFO_ENTRY_0

     

* CFRelease()调用NULL *

奇怪的是,这次崩溃不是100%,而是发生在非常低​​比例的用户身上。我无法在自己的任何设备上重现它。它所发生的iOS版本也没有任何模式,也没有iOS硬件发生的模式。

这是一个不会导致崩溃的文件:

The not-crashy one

这是一个 导致崩溃的文件:

The crashy one

以下是我的生产图片主机(带有云端的s3)中的链接:

(好)  http://d3iq9oupxk0b1m.cloudfront.net/PirateDinosaur/2x/dinoBack._k91G0.jpg

(crashy)  http://d3iq9oupxk0b1m.cloudfront.net/PirateDinosaur/2x/PirateDino.3LHRmc.jpg

即使我使用Imagemagick的identify -verbose <filename>查看它们,我也看不出它们之间有意义的区别。任何jpeg专家都可以权衡吗?

注意:在我要发布的下一个应用版本中,我已经添加了围绕释放NULL引用的警卫,以防止此崩溃:

if (imageSource) { CFRelease(imageSource), imageSource = nil; }
...
if (thumbnail) { CGImageRelease(thumbnail), thumbnail = nil; }

但是,我仍然想知道这个导致这次崩溃的jpeg在世界上有什么问题,所以我的艺术家将来可以避免它。

0 个答案:

没有答案