NSScreen being autoreleased during loadNib()

  • Hi,

    I just encountered a weird problem. Please allow me to introduce some
    related code to explain it:

    - (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 having 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
    SessionListener.m:457

    The rwatch and watch were set at the very beginning of the method2 being
    executed.
    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?

    Thanks,

    Jack.Seraph
  • On Thu, May 30, 2013, at 06:46 PM, Jacky.Seraph Mu wrote:
    > After having executed the line "A Problem happens", I found that the
    > content of the screen (that is, the *screen) changed.

    No, what actually happened is that the stack space/register for `screen`
    was reused by the compiler, so `p *screen` dereferenced whatever value
    got stuffed in the former storage for `screen`. You got (un)lucky and
    this dereference didn't cause an access violation.

    --Kyle Sluder
  • Thank you for comment.

    Then I still got 2 questions:
    1. I saw the compiler reused the register for other purpose when I use -Os
    in gcc to build. But in the instance, I set it to -O0. So I wonder if
    compiler still did such optimization?

    2. From the stack trace of gdb, I can see the an autoreleas-related action.
    #4 0x00007fff8427c230 in (anonymous namespace)::AutoreleasePoolPage::pop ()
    #5 0x00007fff8583cd72 in _CFAutoreleasePoolPop ()

    So my question is that if the autorelease is added by compiler (while
    building) because of the deference for other purpose? If so, how shall I
    prevent this happening? I couldn't see the related action talked about on
    apple's documents. Could you leave any links for this?

    Thanks,

    Jack

    2013/5/31 Kyle Sluder <kyle...>

    > On Thu, May 30, 2013, at 06:46 PM, Jacky.Seraph Mu wrote:
    >> After having executed the line "A Problem happens", I found that the
    >> content of the screen (that is, the *screen) changed.
    >
    > No, what actually happened is that the stack space/register for `screen`
    > was reused by the compiler, so `p *screen` dereferenced whatever value
    > got stuffed in the former storage for `screen`. You got (un)lucky and
    > this dereference didn't cause an access violation.
    >
    > --Kyle Sluder
    >
previous month may 2013 next month
MTWTFSS
    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