Possible reason for EXC_BAD_ACCESS? - ios

I have a legacy app which utilizes Apple's example SimplePing. There is a source file SimplePing.m which contains the next method:
- (void)sendPingWithData:(NSData *)data {
id<SimplePingDelegate> strongDelegate;
...
strongDelegate = self.delegate;
if (...) {
[strongDelegate simplePing:self didSendPacket:...];
}
self.nextSequenceNumber += 1; // CRASH
if (self.nextSequenceNumber == 0) {
self.nextSequenceNumberHasWrapped = YES;
}
}
Crashlytics reports dozens of crashes with stack trace:
Crashed: com.apple.main-thread
EXC_BAD_ACCESS KERN_INVALID_ADDRESS 0x00000009de3bbeb8
libobjc.A.dylib objc_msgSend + 16
MyApp SimplePing.m line 313 -[SimplePing sendPingWithData:]
Foundation __NSFireTimer + 88
CoreFoundation __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 28
CoreFoundation __CFRunLoopDoTimer + 856
CoreFoundation __CFRunLoopDoTimers + 244
CoreFoundation __CFRunLoopRun + 1484
CoreFoundation CFRunLoopRunSpecific + 424
GraphicsServices GSEventRunModal + 100
UIKit UIApplicationMain + 208
MyApp main.swift line 10
libdyld.dylib start + 4
I have not managed to reprodice it yet, and I know a little about this app so far. But I have to begin researching it somehow. I looked through realization of delegates (btw, they are in Swift - if it's relevant), bit did not find anything criminal so far.
As I know, EXC_BAD_ACCESS normally fires when one tries to access deallocated memory. In this concrete case it could mean that [strongDelegate simplePing:self didSendPacket:...] has somehow deallocated self. But as self is a strong reference, it just could not happen at all - am I right?
May you guys drop me some probable scenarios on how could it crash with EXC_BAD_ACCESS on that line? The only my idea is that some memory overwrite have happened.
UPDATE
I was completely wrong with my assumption "But as self is a strong reference ...". self in nether strong, nor weak. It is just unsafe_unretained, as a smart guy explained: https://stackoverflow.com/a/18011581/674548.

Related

Unexplained crash: NSInvalidArgumentException, same view controller instance pushed more than once

I'm seeing an unexplained crash on my iOS app built with SwiftUI. It only affects some users, and I can't manage to reproduce locally.
Here is the stack trace:
Fatal Exception: NSInvalidArgumentException
<_TtGC7SwiftUI41StyleContextSplitViewNavigationControllerVS_19SidebarStyleContext_: 0x110859800>
is pushing the same view controller instance(<_TtGC7SwiftUI41StyleContextSplitViewNavigationControllerVS_14NoStyleContext_: 0x11088a400>)
more than once which is not supported and is most likely an error in the application : `com.myapp`
Fatal Exception: NSInvalidArgumentException
0 CoreFoundation 0x1893a186c __exceptionPreprocess
1 libobjc.A.dylib 0x19e3bcc50 objc_exception_throw
2 UIKitCore 0x18b575514 -[UINavigationController pushViewController:transition:forceImmediate:]
3 UIKitCore 0x18b5751f4 -[UINavigationController pushViewController:animated:]
4 UIKitCore 0x18b6047c8 __45-[UISplitViewControllerPanelImpl showColumn:]_block_invoke
5 UIKitCore 0x18b57eda8 -[UINavigationController _executeSplitViewControllerActions:]
6 UIKitCore 0x18b6045bc -[UISplitViewControllerPanelImpl showColumn:]
7 UIKitCore 0x18b5e4c54 -[UISplitViewController showColumn:]
8 SwiftUI 0x1903784f4 closure #1 in closure #1 in NavigationBridge_PhoneTV.push(_:onto:animated:)
9 SwiftUI 0x19042728c thunk for #escaping #callee_guaranteed () -> ()
10 UIKitCore 0x18c23f544 -[_UIAfterCACommitBlock run]
11 UIKitCore 0x18bd6700c _runAfterCACommitDeferredBlocks
12 UIKitCore 0x18bd559a0 _cleanUpAfterCAFlushAndRunDeferredBlocks
13 UIKitCore 0x18bd89bb4 _afterCACommitHandler
14 CoreFoundation 0x18931c358 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__
15 CoreFoundation 0x1893165c4 __CFRunLoopDoObservers
16 CoreFoundation 0x189316b74 __CFRunLoopRun
17 CoreFoundation 0x18931621c CFRunLoopRunSpecific
18 GraphicsServices 0x1a0ee2784 GSEventRunModal
19 UIKitCore 0x18bd56ee8 -[UIApplication _run]
20 UIKitCore 0x18bd5c75c UIApplicationMain
21 MYAPP 0x100dbecc0 main + 7 (PushupsMode.swift:7)
22 libdyld.dylib 0x188fd66b0 start
Looking at PushupsMode.swift:7 it seems completely unrelated:
import Foundation
extension WorkoutModel {
mutating func startPushups() {
var pushupsCount = 10 + p.intensityOptionPicked * 10
if(round > 6 || round < 3) { // <<--- this is the line crashing
pushupsCount = Int(pushupsCount / 2)
}
// More code after that point
}
}
The round variable is defined in another file, but there's nothing really significant around it:
import Foundation
import SwiftUI
struct WorkoutModel: Identifiable {
// bunch of stuff before
var round: Int = -1
// bunch of stuff after
}
Obviously looking at the error message, it seems like something is getting pushed twice... however since I'm using SwiftUI I'm not entirely sure how I could have even done that.
Any pointers would be appreciated!
Your problem may be that you are defining pushupsCount as an Int( on PushupsMode.swift:8 which is causing the exception on :7 from :8 failing pre-execution. Try defining it as pushupsCount = Int pushupsCount / 2 .
Using pushViewController:transition:forceImmediate is not a good idea because pushViewController:animated will be calling on this undocumented method. Rather than changing transition this way you can use other documented methods for changing animation. This thread might be helpful for you. You will also need to add guard in pushViewController:animated and will also need to set transition.duration. Calling pushViewController again and again is perhaps causing crash of app.
This problem is caused when you place your navigationLink inside of a List with observed data.
How to fix :
Remove NavigationLink from inside of the list and place it outside.

EXC_BAD_ACCESS when object released mid-function

I have a class with a property
#property (nonatomic, copy) MyObject *currentObject;
and a function that looks like this:
- (void)handleExternalChange {
#synchronized (self) {
MyObject *newObject = [self.externalStore getObject];
//Business logic...
self.currentObject = newObject;
}
}
I am seeing a crash objc_msgSend() selector name: copyWithZone: occasionally when i hit the self.currentObject = newObject line.
I presume this is because the externalStore released the object returned by getObject on another thread and by the time it got down to the setter it was gone.
Does this conclusion seem right? If so is there a recommended way to fix this?
UPDATE:
Here's some of the stack trace
Application Specific Information:
objc_msgSend() selector name: copyWithZone:
0 libobjc.A.dylib 0x000000018149ef30 objc_msgSend + 16
1 libobjc.A.dylib 0x000000018149c2d4 objc_setProperty_nonatomic_copy + 44
2 MyApp 0x0000000100115cb4 -[MyClass handleExternalChange] (MyClass.m:117)
3 CoreFoundation 0x00000001829ee22c __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 16
4 CoreFoundation 0x00000001829ed930 _CFXRegistrationPost + 396
5 CoreFoundation 0x00000001829ed6ac ___CFXNotificationPost_block_invoke + 56
6 CoreFoundation 0x0000000182a5cb9c -[_CFXNotificationRegistrar find:object:observer:enumerator:] + 1500
7 CoreFoundation 0x000000018292fbf4 _CFXNotificationPost + 372
8 Foundation 0x00000001834366bc -[NSNotificationCenter postNotificationName:object:userInfo:] + 64
MyObject *newObject = [self.externalStore getObject];
That method shouldn't be named get* anything, but that isn't likely to be the cause of the issue. Nor is it likely to be a threading issue (at least not directly).
This sounds more like there is some state related to the copyWithZone: that isn't handled correctly. How is the copy method implemented? Specifically, is it correctly copying all state and bumping reference counts or does it try to cheat by doing some kind of a byte copy?

KERN_PROTECTION_FAILURE (stack overflow) in libobjc dealloc

I recently received a crash report that looks like this:
0 libobjc.A.dylib 0x0000000193dfea88 object_cxxDestructFromClass(objc_object*, objc_class*) + 0
1 libobjc.A.dylib 0x0000000193e0bf34 objc_destructInstance + 88
2 libobjc.A.dylib 0x0000000193e0bf8c object_dispose + 24
3 My App 0x00000001000d88fc -[CCAction dealloc] + 44
4 My App 0x00000001000e6bf8 -[CCActionSequence .cxx_destruct] + 36
5 libobjc.A.dylib 0x0000000193dfeb18 object_cxxDestructFromClass(objc_object*, objc_class*) + 144
6 libobjc.A.dylib 0x0000000193e0bf34 objc_destructInstance + 88
7 libobjc.A.dylib 0x0000000193e0bf8c object_dispose + 24
8 My App 0x00000001000d88fc -[CCAction dealloc] + 44
9 My App 0x00000001000e6bf8 -[CCActionSequence .cxx_destruct] + 36
10 libobjc.A.dylib 0x0000000193dfeb18 object_cxxDestructFromClass(objc_object*, objc_class*) + 144
11 libobjc.A.dylib 0x0000000193e0bf34 objc_destructInstance + 88
12 libobjc.A.dylib 0x0000000193e0bf8c object_dispose + 24
13 My App 0x00000001000d88fc -[CCAction dealloc] + 44
14 My App 0x00000001000e6bf8 -[CCActionSequence .cxx_destruct] + 36
...and it continues on like this forever. Some kind of infinite recursion happening in dealloc that is causing a stack overflow.
There are only 2 method calls that are visible to me and one of them is .cxx_destruct which is an internal private method used by ARC. The other is the dealloc method of CCAction which only has a log statement in it:
-(void) dealloc {
CCLOGINFO(#"cocos2d: deallocing %#", self);
}
The crash is really hard to reproduce; I've only seen it once. However my app has not been released to the public yet so I'd really like to figure out what is causing it. Any help debugging this would be greatly appreciated.
I am using Cocos2D 3.3.0 and iOS 8.1
If you are using ARC, sending messages to self in dealloc doesn't work like how it used to in manual memory management. ARC does all of the cleanup/disposing in .cxx_destruct BEFORE calling dealloc, so sending messages to self in dealloc will cause undefined behavior - most probably crashes. Unlike in manual memory management where you can send messages to self in dealloc before calling [super dealloc].
From your code, it looks like CCLogInfo is sending a message to self, most probably [self description] (assuming CCLogInfo parameters are just a format string with arguments). This will cause a crash, but I'm not sure why it is causing recursion - can you share the code to CCLogInfo?

MKMapView autorelease not calling dealloc after UIViewController is popped

I have the following code in class A:
UIViewController *vc = [self viewControllerForItem:item];
where the viewControllerForItem method in my app delegate returns a UIViewController based on my item i.e.
vc = [[[MyCustomViewController alloc] init] autorelease];
return vc;
I then push the view controller:
[self.navigationController pushViewController:vc animated:YES];
This VC i'm trying to push is a MKMapView and I inserted a log statement in the dealloc method to see if it's being called. In my memory usage, the growth is increasing pretty rapidly.
However, when I add the following code after pushing the VC:
[vc release];
my MKMapView class calls the dealloc method.
Of course this would be a simple solution if the MKMapView class was the only class returned by my app delegate (or I could just check if the VC's class is my MKMapView class). However, I would like to solve the root problem of this.
Why is the dealloc not being called if I set autorelease on my view controller?
How is it possible that I can add [vc release] to the view controller even though autorelease is used on that vc?
Thanks
Edit:
Here's some additional info. I have the viewControllerForItem class in my app delegate. I'm returning the auto released object into my other manager class where I then push the view controller. Is the retain count being messed up when I return an autoreleased object, and then push it in some other class?
This is the backtrace / callstack right when I push the VC and when the mkmapview's didDissappear is called:
pushVC: (
0 NewHampshire 0x00254cdf -[CustomViewController navigateToRowId:withLinkBehavior:animated:] + 2111
1 NewHampshire 0x002534c9 -[CustomViewController webView:shouldStartLoadWithRequest:navigationType:] + 841
2 UIKit 0x02caf288 -[UIWebView webView:decidePolicyForNavigationAction:request:frame:decisionListener:] + 318
3 UIKit 0x02cb1854 -[UIWebViewWebViewDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:] + 77
4 CoreFoundation 0x05d0bd1d __invoking___ + 29
5 CoreFoundation 0x05d0bc2a -[NSInvocation invoke] + 362
6 CoreFoundation 0x05d0bdaa -[NSInvocation invokeWithTarget:] + 74
7 WebKit 0x0a4d811d -[_WebSafeForwarder forwardInvocation:] + 157
8 CoreFoundation 0x05d076da ___forwarding___ + 458
9 CoreFoundation 0x05d074ee _CF_forwarding_prep_0 + 14
10 CoreFoundation 0x05d0bd1d __invoking___ + 29
11 CoreFoundation 0x05d0bc2a -[NSInvocation invoke] + 362
12 WebCore 0x09533b29 _ZL20HandleDelegateSourcePv + 121
13 CoreFoundation 0x05ca083f __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
14 CoreFoundation 0x05ca01cb __CFRunLoopDoSources0 + 235
15 CoreFoundation 0x05cbd29e __CFRunLoopRun + 910
16 CoreFoundation 0x05cbcac3 CFRunLoopRunSpecific + 467
17 CoreFoundation 0x05cbc8db CFRunLoopRunInMode + 123
18 GraphicsServices 0x059749e2 GSEventRunModal + 192
19 GraphicsServices 0x05974809 GSEventRun + 104
20 UIKit 0x02a6ed3b UIApplicationMain + 1225
21 NewHampshire 0x000150dd main + 125
22 libdyld.dylib 0x04fab70d start + 1
)
disappear: (
0 NewHampshire 0x0014631d -[CustomAdvancedGPSMapViewController viewDidDisappear:] + 173
1 UIKit 0x02b85bac -[UIViewController _setViewAppearState:isAnimating:] + 341
2 UIKit 0x02b86328 -[UIViewController __viewDidDisappear:] + 150
3 UIKit 0x02b86461 -[UIViewController _endAppearanceTransition:] + 306
4 UIKit 0x02ba549a -[UINavigationController navigationTransitionView:didEndTransition:fromView:toView:] + 738
5 UIKit 0x02b9d403 __49-[UINavigationController _startCustomTransition:]_block_invoke + 206
6 UIKit 0x03176740 -[_UIViewControllerTransitionContext completeTransition:] + 99
7 UIKit 0x02a63454 __53-[_UINavigationParallaxTransition animateTransition:]_block_invoke105 + 680
8 UIKit 0x02ad1005 -[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:] + 306
9 UIKit 0x02abac6c -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 267
10 UIKit 0x02abaf58 -[UIViewAnimationState animationDidStop:finished:] + 80
11 QuartzCore 0x028b2a44 _ZN2CA5Layer23run_animation_callbacksEPv + 304
12 libdispatch.dylib 0x04d194b0 _dispatch_client_callout + 14
13 libdispatch.dylib 0x04d0775e _dispatch_main_queue_callback_4CF + 340
14 CoreFoundation 0x05d7ca5e __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 14
15 CoreFoundation 0x05cbd6bb __CFRunLoopRun + 1963
16 CoreFoundation 0x05cbcac3 CFRunLoopRunSpecific + 467
17 CoreFoundation 0x05cbc8db CFRunLoopRunInMode + 123
18 GraphicsServices 0x059749e2 GSEventRunModal + 192
19 GraphicsServices 0x05974809 GSEventRun + 104
20 UIKit 0x02a6ed3b UIApplicationMain + 1225
21 NewHampshire 0x0001507d main + 125
22 libdyld.dylib 0x04fab70d start + 1
)
Solution: Although the responses in this post didn't provide the exact solution to my problem, Darren definitely steered me into the correct direction using the instruments tool. I found the culprit to be a CABasicAnimation object that was not being properly released.
in the viewWillDisappear method, I added the following for the CABasicAnimation object:
self.rotationAnimation.delegate = nil;
self.rotationAnimation = nil;
Use Instruments to track the retain/release history of CustomAdvancedGPSMapViewController and/or MKMapView :
In Xcode, select "Product > Profile" from the menu.
When Instruments starts, select the "Allocations" template.
If your app starts automatically, click the "Stop" button to stop it.
Click the "i" button on the Allocations instrument, and check "Record reference counts".
Select "View > Extended Detail" from the menu.
Click the "Record" button to start your app, and wait for your app to start in the simulator.
In the simulator, use your app to navigate to the CustomAdvancedGPSMapViewController.
In Instruments, click the "Pause" button
Use the search field in the top-right of the window and search for CustomAdvancedGPSMapViewController. CustomAdvancedGPSMapViewController should appear in the Allocation Summary list.
In the Allocation Summary list, Click the -> arrow next to the CustomAdvancedGPSMapViewController name. This should show that you have one instance of CustomAdvancedGPSMapViewController active in your app.
Click the -> arrow next to address. This will display the retain/release history for this CustomAdvancedGPSMapViewController instance.
Un-pause Instruments, return to the simulator, and dismiss your CustomAdvancedGPSMapViewController and return to the point where you believe the controller should be deallocated.
Return to Instruments, click "Pause" again, and look at the updated retain/release history.
The first event in the retain/release history should be "malloc". Select this row and the Extended Detail view in the right side of the window will display the stack trace for this allocation. You should see your own code in the stack trace. Double-click your code in the stack trace and you should see your line of code that allocated the the CustomAdvancedGPSMapViewController instance.
Above the code view, click the "History" tab to return to the history list.
The last event in the retain/release history should be "free". If that's not the case there may be a leak. Inspect the retain/release history and look for an unmatched retain. There may be a lot of noise, related to CoreAnimation, etc. Look for events in which your code appears in the stack trace.
Compare the retain/release history with a different view controller that is not leaking.
If CustomAdvancedGPSMapViewController isn't leaking, try inspecting the history of MKMapView.
The code which you have written is correct and you should not be releasing vc since it is been autoreleased already.
-(UIViewController *) viewControllerForItem: (Item*)item
{
/* create controller for the item --
* alloc init with increase the retain count of your object by 1
* autorelease will reduce the retain count of the object by 1
*/
return [[[MyCustomViewController alloc] init] autorelease];
}
UIViewController *vc = [self viewControllerForItem:item];
[self.NavigationController pushViewController:vc];
You cannot release 'vc' since you dont own it, in the sense you have not done 'alloc init' or 'retain' for it.
I have faced issues with Mapview's not releasing the memory even after getting released. It seems to be an apple bug and this memory will be destroyed only when you get a memory warning for mapview. But you can force the release by doing a hack.
Changing the mapType appears to release the memory the mapview is holding. So try resetting the mapType just before the release of the mapview object in mapviewcontroller. You can see the memory going down just after that statement is executed.
- (void)dealloc
{
// this is a trick for releasing memory
__mapView.mapType = MKMapTypeStandard;
[__mapView removeFromSuperview];
__mapView.delegate = nil;
[__mapview release];
[super dealloc];
}
Hope it helps.

Cocos2d, iOS and XCode: how can I debug/understand this stacktrace?

I am developing a Cocos2d 2.0 game and can't quiet get around on why my App is crashing.
The console output is as following:
2013-02-08 10:52:08.298 AppName[994:15203] cocos2d: CCSpriteBatchNode: resizing TextureAtlas capacity from [29] to [40].
2013-02-08 10:52:08.299 AppName[994:15203] cocos2d: CCSpriteBatchNode: resizing TextureAtlas capacity from [40] to [54].
2013-02-08 10:52:08.300 AppName[994:15203] cocos2d: CCSpriteBatchNode: resizing TextureAtlas capacity from [54] to [73].
(lldb)
The "game scene" loads and crashes immediately. I can see that has to do with CCSpriteBatchNode but I have absolutely no idea on where exactly the code fails. If I add a breakpoint it is not of much use as it will trigger way to many times before reaching the exact moment when it fails.
What does (lldb) mean? Is there a way to have a more explicit stacktrace? I used to work in Java and Eclipse and there was possible to read in English the full stacktrace.. I whish it was as simle using XCode.
You are probably getting one of those nasty EXC_BAD_ACCESS buggers. nope, no exceptions. For example
#try {
// this is caught
// NSMutableArray *ar = [NSMutableArray array];
// [ar addObject:nil];
// this is caught
// NSMutableDictionary *dic = [NSMutableDictionary dictionary] ;
// [dic setObject:#"a" forKey:nil];
// this crashes , no exception
// NSLog("21");
// and this will cause a message sent to a dealloced instance (zombie).
// no exception, just a bad crash.
GEIntEffect *eff = [GEIntEffect intEffectWithString:#"*1.1"
withOrder:geEffectOrderFightMagic
andImpact:geEffectImpactPositive];
[eff release];
NSLog([eff description]);
[[GameSpecs sharedGameSpecs] setupBattlesInitialSpecs];
// with a comment
}
#catch (NSException *e) {
MPLOGERROR(#"*** an exception [%#] occured while writing the game specs, continuing.\n%#\n\n%#",
e.description,
e.callStackSymbols,
e.callStackReturnAddresses);
}
the first two are trapped and the log statement is explicit, spewing me the stack trace in the log. The NSLog("21") ... ooops, forgot the "#" crashes badly. The fourth example, wrongly releasing an object before use ... well u know what that does. I can only suggest you :
check all your warnings (i had one on the bad NSLog)
Profile your app for zombies, using instruments. A message sent to a dealloced object will also crash nasty.
although there is a performance penalty, ie dont overdo it, some strategically placed try/catch blocks can help immensely. Typically, i wrap any 'update' method in Debug, removing the try/catch in Release.
recheck all your warnings :)
best of luck.
ps : here is what the log looks like when i trap an exception. The offsets are not to a 'line of code', symbolicating allows for that. But, typically, i have enough info from the trace to narrow it down to real close. :
-[MPGameSequencer sequenceInitState] : * an exception [* -[__NSArrayM insertObject:atIndex:]: object cannot be nil] occured while writing the game specs, continuing.
(
0 CoreFoundation 0x028de02e __exceptionPreprocess + 206
1 libobjc.A.dylib 0x022bbe7e objc_exception_throw + 44
2 CoreFoundation 0x02891b6a -[__NSArrayM insertObject:atIndex:] + 314
3 CoreFoundation 0x02891a20 -[__NSArrayM addObject:] + 64
4 Battles 0x00221c49 -[MPGameSequencer sequenceInitState] + 809
5 Battles 0x0021e359 -[MPGameSequencer nextFrame:] + 121
6 Battles 0x00067324 -[CCTimer update:] + 308
7 Battles 0x00070444 -[CCScheduler update:] + 772
8 Battles 0x0009dc81 -[CCDirectorIOS drawScene] + 225
9 Battles 0x0009ef44 -[CCDirectorDisplayLink mainLoop:] + 52
10 QuartzCore 0x007c32d2 _ZN2CA7Display11DisplayLink8dispatchEyy + 110
11 QuartzCore 0x007c375f _ZN2CA7Display16TimerDisplayLink8callbackEP16__CFRunLoopTimerPv + 161
12 CoreFoundation 0x0289d376 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 22
13 CoreFoundation 0x0289ce06 __CFRunLoopDoTimer + 534
14 CoreFoundation 0x02884a82 __CFRunLoopRun + 1810
15 CoreFoundation 0x02883f44 CFRunLoopRunSpecific + 276
16 CoreFoundation 0x02883e1b CFRunLoopRunInMode + 123
17 GraphicsServices 0x035e57e3 GSEventRunModal + 88
18 GraphicsServices 0x035e5668 GSEventRun + 104
19 UIKit 0x00e9165c UIApplicationMain + 1211
20 Battles 0x000c2bce main + 270
21 Battles 0x00002a15 start + 53
)

Resources