A question about NSScreen being autoreleased during loadNib()

  • Hi,

    I am OSX developer. The problem I encountered is described as below:

    - (void)method1:(NSObject *)arg1
          contextInfo:(NSObject *)arg2
      [self method2:arg1
                screen:[self.windowController window].screen];

    - (void)method2:(NSObject *)arg1
                screen:(NSScreen *)screen
      MyWindowController *myWindowController      [[MyWindowController alloc] initWithWindowNibName:@"MyWindow"];
      NSWindow *aWindow = [MyWindowController window];  // A Problem happens

    After executed the line "A Problem happens", I found that the content of
    the screen (that is, the *screen) changed.

    (gdb) p *screen
    $15 = {
      <NSObject> = {
        isa = 0x7fff788a6598        xxxxxxxx changed
      members of NSScreen:
      _frame = {
        origin = {
          x = -4353346,              xxxxxxx changed
          y = -234234
        size = {
          width = -35252435,            xxxxxxxx changed
          height = -3452663,              xxxxxxxx changed
      _depth = 520,
      _screenNumber = 2077752383,
      _auxiliaryStorage = 0x0

    At the very beginning, I thought there could have been a stack overflow or
    memory corruption that resulted in this issue. But then I used gdb to watch
    the when *screen is changed. And I also thought that perhaps due to a
    memory corruption, screen has been released unexpectedly. So I also
    rwatched the screen and *screen. But what I got is only that:

    (Please forgive me changed some log because I cannot release the code here.)

    #0 0x00007fff8427824f in objc_msgSend ()
    #1 0x00007fff8c5748e4 in -[NSScreen dealloc] ()
    #2 0x00007fff8581528a in CFRelease ()
    #3 0x00007fff85852efc in -[__NSArrayI dealloc] ()
    #4 0x00007fff8427c230 in (anonymous namespace)::AutoreleasePoolPage::pop ()
    #5 0x00007fff8583cd72 in _CFAutoreleasePoolPop ()
    #6 0x00007fff8c07c172 in loadNib ()
    #7 0x00007fff8c07b88c in +[NSBundle(NSNibLoading)
    _loadNibFile:nameTable:withZone:ownerBundle:] ()
    #8 0x00007fff8c1ce5bc in +[NSBundle(NSNibLoading)
    loadNibFile:externalNameTable:withZone:] ()
    #9 0x00007fff8c20160b in -[NSWindowController loadWindow] ()
    #10 0x00007fff8c2012e5 in -[NSWindowController window] ()
    #11 0x000000010003c3c9 in -[SessionListener method2:screen:]
    (self=0x10220caa0, _cmd=0x100261922, arg1=0x10209ede0, screen=0x1020b7d20)
    at SessionListener.m:307
    #12 0x000000010003d3f4 in -[SessionListener method1:contextInfo:]
    (self=0x10220caa0, _cmd=0x1002618a0, arg1=0x10206b950, arg2=0x0) at

    The rwatch and watch were set at the very beginning of the method2 being
    Then I got the first break while executing the "A Problem happens"line with
    above stack trace.

    From my observing, the loading of the window seemed to trigger an
    Autorelease cycle that released the NSScreen.
    But I didn't do anything like autoreleasepool drain or release. So I
    wondered why it happened that way.

    The last thing is that, this issues doesn't always happen. It is very easy
    to reproduce this issue on my 13 and 15 inch retina MBPs(OSX 10.8.2) but
    cannot repro on my other 13 inch MBP non-retina (OSX10.8.2).

    Could any one leave a comment?


  • On 28 May 2013, at 5:50 AM, "Jacky.Seraph Mu" <jackyseraph...> wrote:

    [On a Retina machine, after instantiating an NSWindow from a new window controller, an NSScreen pointer obtained earlier from another window/controller apparently is released, and the debugger shows funny values in its struct members. The backtrace identified with the screen release shows it happens in a cascade from an NSArray, which I'd wager is the static NSScreen screen list.]

    Random comments, most of which are merely suggestive, and some of which you will say are obviously wrong-headed; but if everything you thought was impossible was in fact impossible, you wouldn't have a bug:

    You don't outright say what the consequence of the strange behavior is. Do you crash? Where?

    I'd not be surprised if NSScreen on HiDPI machines worked differently than on "normal" ones. The struct members aren't API, and don't necessarily mean what they obviously meant in earlier versions.

    Are you using ARC?

    If not, do you -retain the screen object while you are interested in it? It would be strange if the current autorelease pool were drained in the course of the code you show, but not impossible.

    If you're not using ARC, have you tried zombie detection?

    Have you run the application against the Allocations instrument, with full retain/release histories captured?

    Does the other debugger (lldb vs gdb) help?

    Just for grins, what do you get when you "po screen"? If it's still an NSScreen, or apparent subclass, overrelease isn't your problem.

    Are you accessing the passed-in NSScreen pointer after the line you flag? How? Does it become "normal" then?

    What do you get if you acquire a fresh NSScreen pointer? Compared to the new value? Compared to the one before the putative release?

    I believe sending -window to your controllers will instantiate the windows. What leads you to believe that window.screen is valid at the time you call it? Is the window on-screen then?

    This is wild even for me, but do you make _any_ changes to the display parameters between the time you acquire the pointer and the time you discover the fault? The API does not _promise_ that NSScreen objects will be per-screen singletons; a change in display configuration might result in the screen list being thrown away. (I'd be astonished if that were so, but there is no contract that it not be.)

    — F

    Fritz Anderson
    Xcode 4 Unleashed: 4.5 supplement for free!
previous month may 2013 next month
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    
Go to today