CGBitmapContext.DrawImage 24 bits to 32 bits with occasional crashes

ManuelCostaManuelCosta PTMember ✭✭

We are experiencing occasional crashes scaling, and drawing a set of images into a new one by using CGBitmapContext and DrawImage. When the app crashes, no manage exception is reported

By looking to the crash log we see that some memory access violation was the cause while stretching a 24 bits image into a specific region of the 32 bit destination. This is happening in 9.1 and we did not see it happening in 8.x.
Meanwhile we'll file a radar bug to Apple, but if you guys think this can be something wrong on our side or Xamarin's, please let us know.

tkx

#

Crash Log

#

OS Version: iOS 9.1 (13B143)
Exception Type: EXC_BAD_ACCESS (SIGABRT) Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000108944f60 Triggered by Thread: 5

which shows the following stack

Thread 5 Crashed: 0 libsystem_kernel.dylib 0x000000019ab63140 pthread_kill + 8 1 libsystem_pthread.dylib 0x000000019ac2cef8 pthread_kill + 112 2 libsystem_c.dylib 0x000000019aad6b78 abort + 140 3 AppName 0x00000001014e5fc8 mono_handle_native_sigsegv (mini-exceptions.c:2386) 4 AppName 0x00000001014f0014 mono_sigsegv_signal_handler (mini.c:6820) 5 libsystem_platform.dylib 0x000000019ac2594c _sigtramp + 68 6 CoreGraphics 0x0000000185963348 CGSConvertRGB888toRGBA8888 + 148 7 CoreGraphics 0x0000000185963348 CGSConvertRGB888toRGBA8888 + 148 8 CoreGraphics 0x00000001858c6d80 RGBA32_image + 2296 9 libRIP.A.dylib 0x0000000185c13160 ripl_Mark + 32 10 libRIP.A.dylib 0x0000000185c1256c RIPLayerBltImage + 972 11 libRIP.A.dylib 0x0000000185c10acc ripc_DrawImage + 700 12 CoreGraphics 0x000000018593d08c CGContextDrawImageWithOptions + 456 13 AppName 0x0000000100119218 wrapper_managed_to_native_CoreGraphics_CGContext_CGContextDrawImage_intptr_CoreGraphics_CGRect_intptr + 136 14 AppName 0x0000000100073010 CoreGraphics_CGContext_DrawImage_CoreGraphics_CGRect_CoreGraphics_CGImage + 208 15 AppName 0x00000001007ac9e4

#

C#

#
    unsafe private UIImage ComposeImageFromEntry(TemplateAnimationEntry entry, int scale, int totalPhotos)
    {
        using (var pool = new NSAutoreleasePool ()) {

            try {
                // Lets compose the image
                int height = (int)((Math.Ceiling (entry.Photos.Length / 4.0)) * EditViewController.tileWidth);

                UIImage imgBlock = null;

                CGImage[] imgs = new CGImage[entry.Photos.Length];


                for (int i = 0; i < entry.Photos.Length; i++) {

                    PhotoInformation pi = entry.Photos [i];
                    INativoAsset asset = PhotoGalleryReader.SynchronousGetAsset (pi.Record.Name);

                    //Get a UIImage
                    using (var img = GetThumbnail (asset)) {
                        if (img != null) {

                            nfloat cropSize = (nfloat)Math.Min (img.Size.Width, img.Size.Height); 

                            using (var cgImg = img.CGImage) {
                                imgs [i] = cgImg.WithImageInRect (new CGRect ((nfloat)((img.Size.Width - cropSize) / 2f), (nfloat)((img.Size.Height - cropSize) / 2f), cropSize, cropSize));
                            }
                        }
                    }

                }



                var w = EditViewController.tileWidth * scale * 4;
                var h = height * scale;

                var bufferSize = w * h * 4;

                var buffer = new byte[bufferSize];

                fixed(byte* data = &buffer[0]) {
                    using (var context = new CGBitmapContext ((IntPtr)data, w, h, 8,
                        w * 4, CGColorSpace.CreateDeviceRGB (), CGImageAlphaInfo.PremultipliedLast)) {
                        // draw the image to the bitmap context
                        // this fills the data variable with the image data
                        context.InterpolationQuality = CGInterpolationQuality.High;
                        var count = entry.Photos.Length;

                        //The crash happens with both sequential and Parallel loops
                        Parallel.For (0, entry.Photos.Length, (i) => {

                                float width = EditViewController.tileWidth * scale; 

                                if (imgs [i] != null) {

                                    var x = width * (i % 4);
                                    var y = h - (float)Math.Truncate ((double)(i / 4) + 1) * width;


                                    context.DrawImage (new CGRect (x, y, width, width), imgs [i]);

                                }
                        });

                        imgBlock = UIImage.FromImage (context.ToImage ());
                    }
                }

                for(int i = 0; i< imgs.Length; i++){
                    imgs[i].Dispose();
                }

                if (entry.Photos.Length == 0)
                    return null;
                else
                    return imgBlock;
            } catch (Exception e) {
                return null;
            }

        }
    }
Sign In or Register to comment.