Nat! bio photo

Nat!

Senior Mull

Twitter Github Twitch

-[NSBitmapImageRep bitmapData] is useless and possibly dangerous

I wanted to do the most basic of all graphics programs. Draw stuff in a bitmap repeatedly and display it. This used to go like this, when I started coding:



10     SCREEN = PEEK (88) + PEEK (89) * 256
20     POKE SCREEN + y * 40 + x, 55

and presto something happened on the screen.

What I thought the way to do this in AppKit was to use a NSBitmapImageRep and use it wrapped in a NSImage to be displayed in a NSImageView:

- (void) applicationDidFinishLaunching:(NSNotification *)aNotification
{
   NSImage   *image;
   unsigned char   *buf;
   
   buf = malloc( 512 * 512 * 3);
   NSLog( @"0) %s bitmap@ %p", __PRETTY_FUNCTION__, buf);
   
   _bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&buf
                                                     pixelsWide:512
                                                     pixelsHigh:512
                                                  bitsPerSample:8
                                                samplesPerPixel:3
                                                       hasAlpha:NO
                                                       isPlanar:NO
                                                 colorSpaceName:NSDeviceRGBColorSpace
                                                   bitmapFormat:0
                                                    bytesPerRow:0
                                                   bitsPerPixel:0];
   NSLog( @"1) %s bitmap@ %p", __PRETTY_FUNCTION__, [_bitmap bitmapData]);
   image = [[[NSImage alloc] initWithSize:NSMakeSize( 512, 512)] autorelease];
   NSLog( @"2) %s bitmap@ %p", __PRETTY_FUNCTION__, [_bitmap bitmapData]);
   [image addRepresentation:_bitmap];
   NSLog( @"3) %s bitmap@ %p", __PRETTY_FUNCTION__, [_bitmap bitmapData]);
   [image setCacheMode:NSImageCacheNever];
   NSLog( @"4) %s bitmap@ %p", __PRETTY_FUNCTION__, [_bitmap bitmapData]);
   [imageView setImage:image];
   NSLog( @"5) %s bitmap@ %p", __PRETTY_FUNCTION__, [_bitmap bitmapData]);
   [imageView display];
   NSLog( @"6) %s bitmap@ %p", __PRETTY_FUNCTION__, [_bitmap bitmapData]);
}

My expectation being, that I could then change the NSBitmapImageRep and then just call -display in my NSImageView to refresh the screen.

This expectation was wrong. I can't do that.

2013-09-08 15:59:50.183 RandomBitmap[2181:303] 0) -[MulleAppDelegate applicationDidFinishLaunching:] bitmap@ 0x107300000
2013-09-08 15:59:50.183 RandomBitmap[2181:303] 1) -[MulleAppDelegate applicationDidFinishLaunching:] bitmap@ 0x107300000
2013-09-08 15:59:50.183 RandomBitmap[2181:303] 2) -[MulleAppDelegate applicationDidFinishLaunching:] bitmap@ 0x107300000
2013-09-08 15:59:50.183 RandomBitmap[2181:303] 3) -[MulleAppDelegate applicationDidFinishLaunching:] bitmap@ 0x107300000
2013-09-08 15:59:50.184 RandomBitmap[2181:303] 4) -[MulleAppDelegate applicationDidFinishLaunching:] bitmap@ 0x107300000
2013-09-08 15:59:50.184 RandomBitmap[2181:303] 5) -[MulleAppDelegate applicationDidFinishLaunching:] bitmap@ 0x107300000
2013-09-08 15:59:50.189 RandomBitmap[2181:303] 6) -[MulleAppDelegate applicationDidFinishLaunching:] bitmap@ 0x107475100

As a code lawyer would say, as soon as I give NSBitmapImageRep my buffer it apparently becomes NSBitmapImageRep's private buffer. And that although I am responsible for freeing it and (ironically) must not free it as long as NSBitmapImageRep is alive. But NSBitmapImageRep apparently may choose to swap out the bitmap with one of its own - and will! Since there is neither some documentation about this nor a notification, when it does that, the value returned by bitmapData is useless, because you can't know, how long the buffer is actually valid. It's undefined and potentially even dangerous.