Nasty bug in App Store version

Discussion in 'Public Game Developers Forum' started by micah, Nov 23, 2009.

  1. micah

    micah Well-Known Member

    Aug 24, 2009
    362
    0
    0
    game developer
    San Francisco
    I've gotten reports that there's a bad bug in Skeleton Key 1.6, which is in the App Store right now, that causes the game to crash whenever you run out of lives (as opposed to submitting your high score to OpenFeint, or letting you continue at zero score).

    This puzzled me, because I tested it several times, in all different possible ways, and I couldn't reproduce the bug. Then I deleted Skeleton Key off my device and got a copy from the App Store with a promo code, and then I could easily reproduce the bug. But obviously I couldn't run it in debug mode.

    There's no reason why this should be happening, since I didn't change any of my code since I submitted to the App Store. So I'm not really sure what to do. Should I go ahead and submit a new binary to the App Store, without changing any of the game code that might have caused the crash, since it's not crashing for me when I test it? Was there just some fluke with the submission process that corrupted part of the binary and that's what's causing the crash, but resubmitting it will maybe fix it? Any suggestions?
     
  2. arkanigon

    arkanigon Well-Known Member

    Dec 24, 2008
    439
    0
    0
    Are you using Xcode? Can you post the code that runs when you run out of lives?

    You've made the new version available for 2.2.1. I'm pretty sure the problem is related to this. Other people have had similar problems in relation to making code compatible for 2.2.1.

    When you run in Debug mode... check for warnings... it may run fine... but there may be a warning that says, "won't work on 2.2.1" or something to that effect...
     
  3. eVp

    eVp Well-Known Member

    Dec 4, 2008
    180
    0
    0
    I assume yes, but have you run the game in release mode? Some code might misbehave when optimized.
     
  4. mobileben

    mobileben Well-Known Member

    Jul 17, 2009
    595
    0
    0
    Lumpy's Handler
    Zgrunturos and San Francisco
    Hey Micah, you still have the .dSYM file for that build? If so, grab the crash logs to see where it is crashing. A few more things.

    -Do you debug in Release mode at all? Or are you always running Debug? We usually run in Debug, but near the end we always run in Release.

    -You maybe should make yourself an ad hoc build that is similar in settings to your App Store distribution build. You can then load this via XCode and see if you get the crash.
     
  5. micah

    micah Well-Known Member

    Aug 24, 2009
    362
    0
    0
    game developer
    San Francisco
    I've only been debugging in Debug mode, not Release mode. That's a good idea, I'll try it. I do still have the .dSYM file. How do I see the crash logs from it?

    Also, the project doesn't have any warnings, nor does it spit out anything I don't tell it to the debug console when you lose all your lives. So it's nothing obvious.

    Anyway, I'm going to try to test things in Release mode now. I'll tell you if I find anything.
     
  6. mobileben

    mobileben Well-Known Member

    Jul 17, 2009
    595
    0
    0
    Lumpy's Handler
    Zgrunturos and San Francisco
    Release mode is always a good idea. Just curious, when you do a distribution build, what target settings did you copy it from? If it is Release, then you don't know for "sure" (not that you ever can be quite 100%) what'll it'll do.

    Crash logs you get one of two ways. When you hook up to Xcode, go to the organizer. It will load them their. Here is a killer thing Apple did that rocks ... you can get crash logs from users that crash. Just do a google search, it'll tell you how. When the user syncs with iTunes, crash logs are downloaded. Note that on hard unit crashes, there usually will be no crash log.

    Oh, things like no warnings really don't tell you how sound a program is. Just that syntactically you were correct in your programming.
     
  7. micah

    micah Well-Known Member

    Aug 24, 2009
    362
    0
    0
    game developer
    San Francisco
    Yeah, I copy from Release.

    Good to know! Ok, I just installed an ad-hoc build and have reproduced the crash with it, and I have the crash log in hand too. Here's the thread that crashed:

    Code:
    Thread 0 Crashed:
    0   libSystem.B.dylib             	0x00090b5c __kill + 8
    1   libSystem.B.dylib             	0x00090b4a kill + 4
    2   libSystem.B.dylib             	0x00090b3e raise + 10
    3   libSystem.B.dylib             	0x000a7e64 abort + 36
    4   libstdc++.6.dylib             	0x00066390 __gnu_cxx::__verbose_terminate_handler() + 588
    5   libobjc.A.dylib               	0x00008898 _objc_terminate + 160
    6   libstdc++.6.dylib             	0x00063a84 __cxxabiv1::__terminate(void (*)()) + 76
    7   libstdc++.6.dylib             	0x00063afc std::terminate() + 16
    8   libstdc++.6.dylib             	0x00063c24 __cxa_throw + 100
    9   libobjc.A.dylib               	0x00006e54 objc_exception_throw + 104
    10  CoreFoundation                	0x00095c7e +[NSObject doesNotRecognizeSelector:] + 106
    11  CoreFoundation                	0x0001ab12 ___forwarding___ + 474
    12  CoreFoundation                	0x00011838 _CF_forwarding_prep_0 + 40
    13  SkeletonKey                   	0x0000add2 -[GSGame restartLevel] (GSGame.mm:449)
    14  Foundation                    	0x0000dd94 __NSFireTimer + 136
    15  CoreFoundation                	0x000574bc CFRunLoopRunSpecific + 2192
    16  CoreFoundation                	0x00056c18 CFRunLoopRunInMode + 44
    17  GraphicsServices              	0x0000436c GSEventRunModal + 188
    18  UIKit                         	0x00003c28 -[UIApplication _run] + 552
    19  UIKit                         	0x00002228 UIApplicationMain + 960
    20  SkeletonKey                   	0x00003fa0 main (main.m:14)
    21  SkeletonKey                   	0x00003f3c start + 44
    It looks like GSGame.mm:449 is causing the problem. That line is:

    Code:
    [manager doStateChange:[GSGameOver class]];
    This method changes Views, and this is switching to the GameOver view. Here's what doStateChange looks like:

    Code:
    - (void) doStateChange:(Class)state {
    	BOOL animateTransition = TRUE;
    	if(animateTransition) {
    		[UIView beginAnimations:nil context:NULL];
    		[UIView setAnimationDuration:0.5];
    		[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:window cache:YES];
    	}
    	if(viewController.view != nil) {
    		[viewController.view removeFromSuperview]; // remove view from window's subviews
    		[viewController.view release], viewController.view = nil; // release game state
    	}
    	viewController.view = [[state alloc] initWithFrame:CGRectMake(0, 0, IPHONE_WIDTH, IPHONE_HEIGHT) andManager:self];
    	// now set our view as visible
        [window addSubview:viewController.view];
        [window makeKeyAndVisible];
    	if(animateTransition) {
    		[UIView commitAnimations];
    	}
    }
    
    I'm still confused why this is causing this:

    Code:
    10  CoreFoundation                	0x00095c7e +[NSObject doesNotRecognizeSelector:] + 106
    I'll keep working on it, but any insight? I'll try building this for OS 3.0 also, instead of 2.2.1, and see if that fixes it. I would still like 2.2.1 support of course, but I might do that as a last resort.
     
  8. arkanigon

    arkanigon Well-Known Member

    Dec 24, 2008
    439
    0
    0
    Do you have a prototype definition for doChangeState in your header file?
     
  9. arkanigon

    arkanigon Well-Known Member

    Dec 24, 2008
    439
    0
    0
    This is a cool idea... I should have done this when I had my crash problem...
     
  10. mobileben

    mobileben Well-Known Member

    Jul 17, 2009
    595
    0
    0
    Lumpy's Handler
    Zgrunturos and San Francisco
    Hmmm ... this may start to be getting out of my comfort zone. We do basically everything in C++ and OpenGl. So I'm not Obj-C and CG savvy.

    As far as what I'm seeing here ...

    Are you explicitly using selectors for any form of callbacks? I believe the animation stuff uses it implicitly. Based on a non-recognized selector ... my guess is an object is trying to call a selector, but that object does not have that selector being called? Or the object is whacked so it doesn't exist. Again. my caveat is I'm not an Obj-C person.

    One possible way of brute force doing this is insert NSLogs all into your restartLevel routine ... find out which one is the last one that calls called before the game visits crash central :D! This probably includes inserting the NSLogs into your doStateChange routine.

    Sorry is it's not a ton of help. Just curious, in your code you use the BOOL animateTransition, but it is always true. Any reason for that?
     
  11. PixelthisMike

    PixelthisMike Well-Known Member

    First thing I would try would be splitting that call into two to see which part is failing:

    Code:
    Class classObject = [GSGameOver class];
    [manager doStateChange:classObject];
    Then you'll be able to establish which of the selectors it is having trouble finding.
     
  12. micah

    micah Well-Known Member

    Aug 24, 2009
    362
    0
    0
    game developer
    San Francisco
    Good idea. I did this, and it's the second one, doStateChange.

    So manager there is of type GameStateManager, and the prototype definition in GameStateManager.h looks like this:

    Code:
    - (void) doStateChange:(Class)state;
    manager is actually of type SkeletonKeyAppDelegate, which inherits from GameStateManager, like so:

    Code:
    @interface SkeletonKeyAppDelegate : GameStateManager <UIApplicationDelegate, OpenFeintDelegate, OFNotificationDelegate> {
    So SkeletonKeyAppDelegate.h does not have a prototype for doStateChange, but GameStateManager.h does. For most of my manager calls I typecast it to (SkeletonKeyAppDelegate*) first, like this:

    Code:
    [(SkeletonKeyAppDelegate*)manager setSharedScoreFinal:score];
    I wasn't typecasting the call to doStateChange though because the prototype for doStateChange isn't defined in SkeletonKeyAppDelegate, so I don't need to. Also, I call doStateChange in all sorts of places around the program (like, when you create a new game) and it works fine. But just in case, I did try typecasting it to SkeletonKeyAppDelegate*, and it doesn't make a difference. It still crashes.

    So brute forcing it with NSLogs won't work here because I can't run this in the debugger, because I have to make an ad-hoc build and install it via iTunes each time I want to reproduce the crash. I could make come up with some other way of logging though, like writing to a file, but that would certainly be a pain. I might have to do it though.

    And yes, the BOOL animateTransition doesn't need to be there. It was actually old debugging code. This was my first game (and first iPhone app, in fact), and the whole framework I'm using actually was taken from the book iPhone Game Development, published by O'Reilly, and modified a bunch (I bought a Rough Cut of the book before it was complete). If I had to do it all over again, I'd use cocos2d :).

    Anyway, still working on this bug. I'll keep you updated if I come up with a fix.
     
  13. PixelthisMike

    PixelthisMike Well-Known Member

    Have you imported GameStateManager.h? I'm guessing you probably have since you're not getting any warnings...
     
  14. mobileben

    mobileben Well-Known Member

    Jul 17, 2009
    595
    0
    0
    Lumpy's Handler
    Zgrunturos and San Francisco
    #14 mobileben, Nov 24, 2009
    Last edited: Nov 24, 2009
    Did you try running the adhoc build thru Xcode? You can do this. I've done it and debugged that way. You cannot do this with the one you submit to Apple, but you can do it with an adhoc that you'd say, give a beta tester. Problem does not occur in a standard release built version BTW? I would think it should...

    Ohh .. i should add, I can't remember if I used NSLog on that adhoc build tho ... I think i ran it in the debugger and debugged via breakpoints, etc. But you could always jury rig global variables to use as a software trigger to break on.
     
  15. PixelthisMike

    PixelthisMike Well-Known Member

    #15 PixelthisMike, Nov 24, 2009
    Last edited: Nov 24, 2009
    Just did some testing and you can use NSLog with an adhoc build. You can view them on the Console tab in the Organizer window. They come up as "<Warning>: NSLog output here". Thought that might be useful to you :)
     
  16. bomber

    bomber Well-Known Member

    Nov 9, 2008
    942
    1
    0
    Normally you can use respondsToSelector to see if you can actually call the function, otherwise there is something wrong in the class hierarchy. It probably tries to call doStateChange of GameStateManager but fails since it's not existing.
     
  17. micah

    micah Well-Known Member

    Aug 24, 2009
    362
    0
    0
    game developer
    San Francisco
    When I try clicking Build and Run when the ad-hoc configuration is active it compiles, installs, shows the Default.png file like it's actually loading, then fails saying "Error from Debugger: The program being debugged is not being run."

    Here's what it says in the console:

    Code:
    This GDB was configured as "--host=i386-apple-darwin --target=arm-apple-darwin".tty /dev/ttys000
    Loading program into debuggerÂ…
    Program loaded.
    target remote-mobile /tmp/.XcodeGDBRemote-14108-29
    Switching to remote-macosx protocol
    mem 0x1000 0x3fffffff cache
    mem 0x40000000 0xffffffff none
    mem 0x00000000 0x0fff none
    run
    RunningÂ…
    Error launching remote program: failed to get the task for process 616.
    Error launching remote program: failed to get the task for process 616.
    The program being debugged is not being run.
    The program being debugged is not being run.
    
    Running it with the debug configurations works fine though. And then running the ad-hoc Skeleton Key but not through the debugger works fine too.
     
  18. mobileben

    mobileben Well-Known Member

    Jul 17, 2009
    595
    0
    0
    Lumpy's Handler
    Zgrunturos and San Francisco
    Have you tried to build using a Release mode only (no adhoc) and to a Build and Run. I am not sure why that adhoc didn't work. I'm not in front of my Mac to see what my settings are. There must be some subtle setting set up. But our adhoc is a duplicate of the Release version.

    It should. PixelthisMike also has an adhoc build running thru Xcode as well.

    Dumb question. This is an adhoc you would use to distribute to others, right? So entitlements, etc are all set up properly?

    I'd first try the Release mode and see if it works. If it doesn't, I'd delete the app completely and retry the adhoc thru Xcode.
     
  19. micah

    micah Well-Known Member

    Aug 24, 2009
    362
    0
    0
    game developer
    San Francisco
    It appears that I've fixed the problem, but I have no idea why.

    In GSGame.mm, where I switch to the GSGameOver view, I changed this line:

    Code:
    [(SkeletonKeyAppDelegate*)manager doStateChange:[GSGameOver class]];
    To these lines:

    Code:
    if([(SkeletonKeyAppDelegate*)manager respondsToSelector:@selector(doStateChange:)]) {
    	[(SkeletonKeyAppDelegate*)manager doStateChange:[GSGameOver class]];
    }
    And it doesn't crash when you run out of lives in the ad-hoc build. And it switches to the GSGameOver view without a problem too.

    I tested it twice, just to make sure it wasn't something I was overlooking. The first block of code crashes, every time, and the second block of code hasn't crashed on me yet. Why?

    And ... should I go ahead and submit to Apple like this, or am I asking for more trouble?
     

Share This Page