3

Developing an app for OSX. There's still bugs and it crashes in release builds.

However, it runs in debug builds, when there's a blank NSLog statement in a few spots. If the NSLog statements are removed, the app crashes on run.

The first statement, in a run loop (prints calculated ticks and drawn frames, it simulates a fluid in an NSView) NSLog(@"%d ticks, %d frames", ticks, frames);

The second statement, in the tick method that gets called every loop, NSLog(@"");

In debug mode, running from Xcode, it works just fine with these two statements. If either is removed, it crashes. After several hours searching, I can't find any reference to apps crashing without blank NSLog statements.

Edit: The final question is: Is there anything I should look out for that might be causing this?

Edit 2: The run and tick methods are

-(void) run {
    timeval start = gettime();
    timeval end = gettime();
    float dt = 1./60;
    self.E.dt = dt;
    float tick = 1e6*dt;
    float unprocessed;
    int ticks = 0;
    int frames = 0;
    timeval now;
    while ( TRUE ) {
        now = gettime();
        unprocessed += diff(end, now)/tick;
        end = now;
        BOOL shouldRender = true; // set false to limit framerate to tickrate
        while ( unprocessed >= 1 ) {
            ticks++;
            [self tick];
            unprocessed -= 1;
            shouldRender = true;
        }

        if ( shouldRender ) {
            frames++;
        }

        if ( diff(start, gettime()) > 1000000 ) {
            start.tv_sec += 1;
            NSLog(@"%d ticks, %d frames", ticks, frames);
            frames = 0;
            ticks = 0;
        }
    }
}

-(void) tick {
    NSLog(@"");
    NSDictionary* fs = [NSDictionary dictionaryWithObjectsAndKeys:self.u, @"u", self.v, @"v", self.p, @"p", self.T, "@T", nil];
    NSDictionary* gs = [self.E evolve:fs];
    [self.u swap:[gs objectForKey:@"u"]];
    [self.v swap:[gs objectForKey:@"v"]];
    [self.p swap:[gs objectForKey:@"p"]];
    [self.T swap:[gs objectForKey:@"T"]];
    [self.view setNeedsDisplay:YES];
}

Edit 3: This is clearly an issue with LLVM. When I compile with GCC, I get no crash. Unfortunately there's an extraordinary amount of memory leaks now due to no ARC. Confusion level increased.

Edit 4: Backtrace

Crashed Thread:  2

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000010

External Modification Warnings:
Debugger attached to process.

VM Regions Near 0x10:
--> 
    __TEXT                 0000000103a9b000-0000000103a9c000 [    4K] r-x/rwx SM=COW  /Users/USER/Library/Developer/Xcode/DerivedData/Splash-ahjwbarsbqqbuzfcnxstxpslekdi/Build/Products/Debug/Splash.app/Contents/MacOS/Splash

Application Specific Information:
objc_msgSend() selector name: copy
objc[32100]: garbage collection is OFF

Thread 2 Crashed:
0   libobjc.A.dylib                 0x00007fff8e43ee90 objc_msgSend + 16
1   com.apple.CoreFoundation        0x00007fff87edf8ac -[__NSPlaceholderDictionary initWithObjects:forKeys:count:] + 668
2   com.apple.CoreFoundation        0x00007fff87efcd13 +[NSDictionary dictionaryWithObjectsAndKeys:] + 1203
3   com.mbarriault.Splash           0x0000000103a9d488 -[Game tick] + 328 (Game.m:95)
4   com.mbarriault.Splash           0x0000000103a9d2a9 -[Game run] + 361 (Game.m:76)
5   com.apple.Foundation            0x00007fff9020874e -[NSThread main] + 68
6   com.apple.Foundation            0x00007fff902086c6 __NSThread__main__ + 1575
7   libsystem_c.dylib               0x00007fff8dba18bf _pthread_start + 335
8   libsystem_c.dylib               0x00007fff8dba4b75 thread_start + 13

Thread 2 crashed with X86 Thread State (64-bit):
  rax: 0x0000000103aa5a00  rbx: 0x0000000000000004  rcx: 0x0000000000000000  rdx: 0x0000000000000000
  rdi: 0x0000000103aa3071  rsi: 0x00007fff8f9ea7d0  rbp: 0x0000000107b47970  rsp: 0x0000000107b47900
   r8: 0x0000000000000004   r9: 0x0000000103aa5ab0  r10: 0x0000000000000001  r11: 0x0000000000000000
  r12: 0x0000000000000003  r13: 0x0000000107b47928  r14: 0x0000000107b479a0  r15: 0x0000000107b47980
  rip: 0x00007fff8e43ee90  rfl: 0x0000000000010202  cr2: 0x0000000000000010
Logical CPU: 3

I removed ID information and the logs for threads that didn't crash, as the whole log went over the post length limit.

Edit 5: Changing the dictionary creation from NSDictionary:dictionaryWithObjectsAndKeys: to NSDictionary:dictionaryWithObjects:forKeys: seems to have fixed all my problems. I'm not entirely certain why, but I'll take it! Thanks everyone!

Edit 6: The correct answer, believe if you will, was a simple typo in a string.

  • Yes, this is weird. What's your question? – benzado Feb 23 '12 at 22:47
  • It's hard to hazard a guess with so little information. Can you post more of the code in the loop? – Jose Ibanez Feb 23 '12 at 23:13
  • 3
    A few thoughts: Concurrency? Race conditions? I've seen NSLogs affect the outcome of race condition related bugs before. – Will Pragnell Feb 23 '12 at 23:15
  • +1 interesting situation. This question should probably be closed as not general enough too ;) – Dan Rosenstark Feb 23 '12 at 23:43
  • @WillPragnell is on the right track. This code is time sensitive and using an NSLog will affect the timing. Is this code threaded? – ThomasW Feb 23 '12 at 23:45
  • An instance of the class is separated into it's own thread in the App Delegate's `applicationDidFinishLaunching`, but only once. `[NSThread detachNewThreadSelector:@selector(run) toTarget:self.game withObject:nil]` – Mike Barriault Feb 23 '12 at 23:47
  • 1
    You should post the backtrace of the crash. – ThomasW Feb 23 '12 at 23:48
  • What graphics technology are you using for rendering? If the graphics are not thread safe it will be a problem. – ThomasW Feb 23 '12 at 23:49
  • @ThomasW I'm just drawing with `NSRectFill` in an NSView subclass' overloaded `drawRect`, but the drawing only happens once with each tick. – Mike Barriault Feb 23 '12 at 23:54
  • @MikeBarriault are you directly calling the `drawRect` method? I'm sure that isn't supported. – ThomasW Feb 24 '12 at 00:08
  • Not directly, but indirectly by calling `setNeedsDisplay:YES` on the view. – Mike Barriault Feb 24 '12 at 00:10
  • The backtrace would probably be helpful. – ThomasW Feb 24 '12 at 00:15
  • I honestly can't figure out how to get that. backtrace isn't a command in lldb, and it doesn't crash using GCC, and Googling hasn't provided any answers. – Mike Barriault Feb 24 '12 at 00:21
  • backtrace is `bt` in lldb, but that isn't what we want here. The backtrace should show up either in the system CrashReporter dialog or the log. See Console.app "User Diagnostic Reports" and "System Diagnostic Reports". – ThomasW Feb 24 '12 at 00:28
  • you should probably fix the code, it is still broken – steve Feb 24 '12 at 04:03

1 Answers1

2

From the look of the backtrace it is crashing when allocating the NSDictionary. Probably one of the object references being used to initialize the NSDictionary is invalid. If you post code from the tick method it could help narrow down what the problem is. Also, if you try debugging with NSZombie on it could tell us which object type it is crashing on.

Edit: OK. Now that I see the tick code, I can see the problem. I didn't see it at first, but you are using the c-string "@T", which you probably intended to be @"T".

Community
  • 1
  • 1
ThomasW
  • 16,981
  • 4
  • 79
  • 106
  • All the code from `tick` is there (the pasted code above happens to be exactly tall enough to show `run`, scroll down to see `tick`). I also considered that there was something invalid, but checking the variables while debugging the crash shows everything properly initiated. – Mike Barriault Feb 24 '12 at 00:53
  • How are you checking the variables? If you are using NSLog to check the variables then the app won't crash. You need to set a breakpoint to check the variables (if you aren't already doing that). – sosborn Feb 24 '12 at 01:03
  • I was just using the LLDB integration with Xcode to few the variables, in the left part of the console panel. On crash, it would stay at the crashpoint to allow for inspection. However, changing the dictionary creation from `NSDictionary:dictionaryWithObjectsAndKeys:` to `NSDictionary:dictionaryWithObjects:forKeys:` seems to have fixed all my problems. I'm not entirely certain why, as both methods are supposed to do the exact same thing (just with slightly different semantics), but appears to have fixed everything. Works even in release mode now! – Mike Barriault Feb 24 '12 at 01:04
  • The exact source of the problem eluded me until I looked at that `dictionaryWithObjectsAndKeys:` code several times. I've updated my answer. Changing to `NSDictionary:dictionaryWithObjects:forKeys:` won't fix your problem, although it might cover the symptoms. – ThomasW Feb 24 '12 at 01:27
  • @ThomasW Wow, I can't believe I missed that. Doesn't explain why nothing is deallocating, but that appears to be a separate issue altogether. Thanks! – Mike Barriault Feb 24 '12 at 02:33