Help with crash log - cocoa

My app is crashing on Lion when it awakes from sleep.
The problem seems to be with a background thread that is looking for weather info.
I'm not sure but I think the crash log is telling me that the autorelease pool is popping objects that are no longer there, can someone help me confirm this?
Here is the relevant details for the Crash log:
Process: myApp [14187] Identifier: myApp Version:
??? (???) Code Type: X86-64 (Native) Parent Process: launchd
[224]
Date/Time: 2011-08-24 18:58:00.581 -0400 OS Version: Mac OS
X 10.7.1 (11B26) Report Version: 9
Crashed Thread: 7
Exception Type: EXC_BAD_ACCESS (SIGSEGV) Exception Codes:
KERN_INVALID_ADDRESS at 0x0000000000000010
Application Specific Information: objc[14187]: garbage collection is
OFF
Thread 7 Crashed: 0 libobjc.A.dylib
0x00007fff9321700b (anonymous
namespace)::AutoreleasePoolPage::pop(void*) + 385 1
com.apple.CoreFoundation 0x00007fff961306a5
CFAutoreleasePoolPop + 37 2 com.apple.Foundation
0x00007fff969350d7 -[NSAutoreleasePool drain] + 154 3
com.piso13.opusDomini 0x00000001000acb91 -[Weather
internalStart] + 417 4 com.apple.Foundation
0x00007fff9698b1ea -[NSThread main] + 68 5 com.apple.Foundation
0x00007fff9698b162 NSThread_main + 1575 6 libsystem_c.dylib
0x00007fff90b068bf _pthread_start + 335 7 libsystem_c.dylib
0x00007fff90b09b75 thread_start + 13
Here is my code for Weather Internal Start:
-(void)internalStart{
pool = [[NSAutoreleasePool alloc] init];
forecast = FALSE;
liveweather = FALSE;
NSString *query = [self generateQuery];
if (query == nil) {
[pool drain];
return;
}
XmlWrapper * xmlWrapper = [[XmlWrapper alloc] initWithQuery:query delegate:self name:#"liveweather"];
[xmlWrapper release];
query = [self generateForecastQuery];
xmlWrapper = [[XmlWrapper alloc] initWithQuery:query delegate:self name:#"forecast"];
[xmlWrapper release];
[pool drain];
}
Should I even be calling [pool drain] ?

create your autorelease pools with bound lifetimes and explicit scopes.
in this case, you store your autorelease pool in an ivar (presumed).
just make it local to the method, like so:
- (void)internalStart
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
//...
[pool drain], pool = nil;
}
the problems that are typically introduced are:
1) autorelease pools are stack based (pools are pushed and popped). by holding onto it, you can easily mess up the stack order.
2) if this class operates in a multithreaded context, you can easily leak pools or destroy the stack order when you push and pop pools from multiple threads.
3) you could also leak pools in multithreaded contexts

Unfortunately, autoreleasepool crashes are some of the hardest to debug. Start with the static analyzer, which can find some things.
Then turn on NSZombies.
Your XmlWrapper object is a bit strange. Why do you immediately release it as soon as you create it? Is this a wrapper around NSURLConnection? You should still hold onto the object so that you can cancel it or clear its delegate when this object is released.
Make sure you're using accessors for all your ivars rather than accessing them directly. Direct access to ivars outside of init and dealloc is the #1 cause of these kinds of crashes in my experience.

Related

UIImage: imageNamed crash

I am having truble while using [UIImage imageNamed:] method
It appeares that crash occured when launching app from killed state and getting an resource image.
All my images are stored in bundle and no issue with background thread.
Following is crash log
Thread : Crashed: com.apple.main-thread
19 UIKit 0x186739714 +[UIImage imageNamed:inBundle:compatibleWithTraitCollection:] + 380
20 UIKit 0x18658cc8c +[UIImage imageNamed:] + 124
This happens on
UIImage * image = [UIImage imageNamed:#"abc.png"];

Continuously write content of a log file into an NSTextview

I'm having trouble with an NSTextview which should continously update with the contents of a log file. The app is a master-detail UI, the master view contains an array of "backup" objects, while the detail view contains an NSTabView with one of the tabs containing the NSTextview.
Basically I want something like a tail -f logfile putting it's output into the NSTextview. Instead of using NSTask etc., I went for binding the NSTextview's "Attributed String" to a property of my "backup" object (so I can set the font):
backup.m
- (NSAttributedString *)logContent
{
NSDictionary *attributes = #{NSFontAttributeName:[NSFont fontWithName:#"Monaco" size:12]};
NSString *str = [NSString stringWithContentsOfURL:theLogfile encoding:NSUTF8StringEncoding error:nil];
if (str) {
NSAttributedString *attrstr = [[NSAttributedString alloc] initWithString:str attributes:attributes];
return attrstr;
} else
return nil;
}
Then I hook an FSEventStream to the logfile which informs a callback everytime the logfile changes. Inside the callback, I manually inform listeners that the property has changed and scroll down the NSTextview:
backup.m
- (void)_fsEventsCallback:(NSArray *)eventPaths{
if ([eventPaths containsObject:theLogfile.path]){
[self willChangeValueForKey:#"logContent"];
[self didChangeValueForKey:#"logContent"];
[_myAppDel.logTextView scrollRangeToVisible:NSMakeRange([[_myAppDel.logTextView string] length], 0)];
}}
The actual remove is done via an NSNotification:
App Delegate.m
- (void)removeBackupObject:(NSNotification *)notification
{
if (notification.object) {
[self.backupsArrayController removeObject:notification.object];
}
}
This works and I like the code better than using an NSTask, but the app occasionally crashes with a strange error when I tell the NSArrayController to remove a "backup" object:
Crashed Thread: 5 Dispatch queue: com.apple.root.low-priority
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Application Specific Information:
*** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSSetM: 0x60000045f1a0> was mutated while being enumerated.'
terminating with uncaught exception of type NSException
abort() called
Application Specific Backtrace 1:
0 CoreFoundation 0x00007fff8aec425c __exceptionPreprocess + 172
1 libobjc.A.dylib 0x00007fff8a7a4e75 objc_exception_throw + 43
2 CoreFoundation 0x00007fff8aec3b64 __NSFastEnumerationMutationHandler + 164
3 Foundation 0x00007fff8d0e3f05 -[NSISEngine chooseOutgoingRowHeadForIncomingRowHead:] + 305
4 Foundation 0x00007fff8d0e1aa8 -[NSISEngine minimizeConstantInObjectiveRowWithHead:] + 114
5 Foundation 0x00007fff8d0e1623 -[NSISEngine optimize] + 147
6 Foundation 0x00007fff8d0e851d -[NSISEngine constraintDidChangeSuchThatMarker:shouldBeReplacedByMarkerPlusDelta:] + 296
7 Foundation 0x00007fff8d0e839e -[NSISEngine tryToChangeConstraintSuchThatMarker:isReplacedByMarkerPlusDelta:undoHandler:] + 420
8 Foundation 0x00007fff8d0d3798 -[NSLayoutConstraint _tryToChangeContainerGeometryWithUndoHandler:] + 462
9 Foundation 0x00007fff8d0d31b3 -[NSLayoutConstraint _setSymbolicConstant:constant:] + 402
10 AppKit 0x00007fff8e2ac4ba -[NSView(NSConstraintBasedLayout) _autoresizingConstraints_frameDidChange] + 247
11 AppKit 0x00007fff8e2ab25f -[NSView setFrameOrigin:] + 901
12 AppKit 0x00007fff8e2b51b6 -[NSView setFrame:] + 259
13 AppKit 0x00007fff8e682c2f -[NSClipView _updateOverhangSubviewsIfNeeded] + 739
14 AppKit 0x00007fff8e2e80a1 -[NSClipView _scrollTo:animateScroll:flashScrollerKnobs:] + 1984
15 AppKit 0x00007fff8e2e76ff -[NSClipView _reflectDocumentViewFrameChange] + 128
16 AppKit 0x00007fff8e2ac0ac -[NSView _postFrameChangeNotification] + 203
17 AppKit 0x00007fff8e2b5852 -[NSView setFrameSize:] + 1586
18 AppKit 0x00007fff8e447bac -[NSTextView(NSPrivate) _setFrameSize:forceScroll:] + 764
19 AppKit 0x00007fff8e3b222f -[NSTextView setConstrainedFrameSize:] + 633
20 AppKit 0x00007fff8e443f70 -[NSLayoutManager(NSPrivate) _resizeTextViewForTextContainer:] + 1025
21 AppKit 0x00007fff8e35133e -[NSLayoutManager(NSPrivate) _recalculateUsageForTextContainerAtIndex:] + 2636
22 AppKit 0x00007fff8e343fb1 _enableTextViewResizing + 211
23 AppKit 0x00007fff8e34a6ef -[NSLayoutManager textStorage:edited:range:changeInLength:invalidatedRange:] + 557
24 AppKit 0x00007fff8e34a4aa -[NSTextStorage _notifyEdited:range:changeInLength:invalidatedRange:] + 149
25 AppKit 0x00007fff8e451a2c -[NSTextStorage processEditing] + 200
26 AppKit 0x00007fff8e44d832 -[NSTextStorage endEditing] + 110
27 Foundation 0x00007fff8d10b434 -[NSMutableAttributedString removeAttribute:range:] + 219
28 AppKit 0x00007fff8e4ca2c1 -[NSTextView setTextColor:] + 156
29 AppKit 0x00007fff8ea19baf -[_NSTextPlugin showValue:inObject:] + 128
30 AppKit 0x00007fff8e314797 -[NSValueBinder _adjustObject:mode:observedController:observedKeyPath:context:editableState:adjustState:] + 846
31 AppKit 0x00007fff8e3143aa -[NSValueBinder _observeValueForKeyPath:ofObject:context:] + 282
32 AppKit 0x00007fff8e314215 -[NSTextValueBinder _observeValueForKeyPath:ofObject:context:] + 43
33 Foundation 0x00007fff8d09af28 NSKeyValueNotifyObserver + 387
34 Foundation 0x00007fff8d0d7ed1 -[NSObject(NSKeyValueObservingPrivate) _notifyObserversForKeyPath:change:] + 1115
35 AppKit 0x00007fff8e306d88 -[NSController _notifyObserversForKeyPath:change:] + 209
36 AppKit 0x00007fff8e4385ff -[NSArrayController didChangeValuesForArrangedKeys:objectKeys:indexKeys:] + 125
37 AppKit 0x00007fff8e62179f -[NSArrayController _removeObjectsAtArrangedObjectIndexes:contentIndexes:objectHandler:] + 724
38 AppKit 0x00007fff8e621d1f -[NSArrayController _removeObjects:objectHandler:] + 502
Before I go into debugging what's going wrong, or implement the NSTask / tail -f approach, I'd like to know:
Are there are more elegant solutions to this problem?
This is an unsynchronized access issue. The notification is executing on one thread and the fsevent callback on another and both of them are accessing the ArrayController's underlying array and the textview at the same time.
Option 1 - Quick and dirty fix
Synchronize access accross threads. This done by acquiring a lock on the particular resource being accessed: the executing thread is gets the lock and all threads that attempt to acess that resource will be blocked until the locking thread releases the lock. More info can be found in the Threadding programming guide
Your code thus becomes:
- (void)_fsEventsCallback:(NSArray *)eventPaths{
if ([eventPaths containsObject:theLogfile.path])
#synchronized(self.logContent) {
[self willChangeValueForKey:#"logContent"];
[self didChangeValueForKey:#"logContent"];
}
#synchronized(_myAppDel.logTextView.string) {
[_myAppDel.logTextView scrollRangeToVisible:NSMakeRange([[_myAppDel.logTextView string] length], 0)];
}
}
}
- (void)removeBackupObject:(NSNotification *)notification
{
if (notification.object) {
#synchronized(self.backupsArrayController) {
[self.backupsArrayController removeObject:notification.object];
}
}
}
This will most likely solve your immediate problem, but however, IT IS A CHEAP AND DIRTY FIX and will effectively make your application's threads wait for each other every time.
Option 2 - The better way
Always update your ui on the main thread and do actual work on secondary threads.
The FSEvents callback is called on a secondary thread, the NSNotification that you are posting is responded to on another secondary thread and all of them operate on objects that are not really thread safe. Generally, NSMutable* objects are thread safe on access but not on mutations. In other words, if you're altering their contents, you'd better pay attention whos is doing what and when. :)
More info on which Cocoa Objects are thread safe and which are not can be found here in the Thread Safety section in the document I referred above. (That is quite a good piece of reading btw)
The idea is to tell the app to update the interface on the main thread, like so:
- (void)_fsEventsCallback:(NSArray *)eventPaths{
if ([eventPaths containsObject:theLogfile.path]){
[self willChangeValueForKey:#"logContent"];
[self didChangeValueForKey:#"logContent"];
[[NSApp delegate] performSelectorOnMainThread:#selector(scrollToWhereWeNeedTo) withObject:nil];
}}
AppDelegate.m
- (void)scrollToWhereWeNeedTo
{
[self.logTextView scrollRangeToVisible:NSMakeRange([[self.logTextView string] length], 0)];
}
- (void)removeBackupObject:(NSNotification *)notification
{
if (notification.object) {
[[NSApp delegate] performSelectorOnMainThread:#selector(removeObjectFromArrayController) withObject:notification.object];
}
}
- (void)removeObjectFromArrayController:(id)theObject
{
[self.backupsArrayController removeObject:theObject];
}
What you are effectively doing here is you are scheduling the scroll operation and the removing object operations on the main thread's runloop, thus eliminating any potential access conflict, because they will be in a queue, one after the other.
Also, please look at any other potential places in your app where access conflicts could happen.
I really hope this helps and does not confuse you even further. Cocoa can be a pain at first but hey, what doesn't kill you makes you stronger!
I solved the problem with the help of Cătălin Stan by executing the removeObject: call on the main thread like so:
- (void)removeBackupObject:(NSNotification *)notification
{
if (notification.object) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.backupsArrayController removeObject:notification.object];
});
}
}

EXC_BAD_ACCESS only on 10.6.8

I am trying to get my app to run on version 10.6 but when I do I get an EXC_BAD_ACCESS exception. When I run it on my computer which has the latest version it runs fine, but for some reason it won't work on versions below 7. Since I don't develop on a 10.6 computer all I have to look at is the crash log:
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000000000000
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Thread 0 Crashed: Dispatch queue: com.apple.main-thread
0 com.apple.CoreFoundation 0x00007fff87604930 CFDictionaryGetValue + 96
1 com.apple.CFNetwork 0x00007fff810814d9 CFHTTPCookieCreateWithProperties + 111
2 com.apple.Foundation 0x00007fff88812f4c -[NSHTTPCookie initWithProperties:] + 29
3 com.apple.Foundation 0x00007fff88813243 +[NSHTTPCookie cookieWithProperties:] + 50
This is the main part of the crash log. It seems to crash trying to get a dictionary value but I'm not exactly sure how to read these.
Okay I was able to solve it. I loaded a cookie on start with a method like this:
- (NSHTTPCookie *)loadCookie {
NSDictionary *properties = [[NSUserDefaults standardUserDefaults] dictionaryForKey:kDefCookie];
return [NSHTTPCookie cookieWithProperties:properties[COOKIE_KEY]];
}
I saved the cookie properties in defaults so I could save the users cookie across sessions. Running on the latest version, this method returned nil for me when there was no cookie stored in defaults. For some reason this doesn't seem to work on 10.6. I changed the method like this and it works perfectly now.
- (NSHTTPCookie *)loadCookie {
NSDictionary *properties = [[NSUserDefaults standardUserDefaults] dictionaryForKey:kDefCookie];
if (properties)
return [NSHTTPCookie cookieWithProperties:properties[COOKIE_KEY]];
else return nil;
}
Thanks Carter Pape fo helping me read the crash log. I focused to much on the cfDictionary part and I didn't read the stuff that came before

IOS 6 MKMapView crashes on [EAGLContext setCurrentContext]

We are developing an iPad application starting from map view with annotations.
By using storyboard when We switch to another view which has an opengl based charting solution (shinobi).
On return to the view with map it has no problem until a touch on the map to move it.
As we try to move map it crashes with exc_bad_access exception at [EAGLContext setCurrentContext]
Any ideas?
Here is the part of the crash log:
OS Version: iOS 6.0 (10A403)
Report Version: 104
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000c
Crashed Thread: 0
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 OpenGLES 0x39974b12 +[EAGLContext setCurrentContext:] + 74
1 VectorKit 0x32c64f0c -[VGLGPU setPaused:] + 120
2 VectorKit 0x32c54db8 -[VKMainLoop updateLinkState] + 492
3 VectorKit 0x32c54950 -[VKScreenCanvas _updateDisplayStatus:] + 104
4 VectorKit 0x32ccea9a -[VKScreenCanvas setGesturing:] + 254
5 MapKit 0x34defc3c -[MKMapView _willStartUserInteraction] + 48
6 MapKit 0x34de891a -[MKMapGestureController beginGesturing] + 50
7 MapKit 0x34de8c6c -[MKMapGestureController handlePan:] + 252
8 UIKit 0x379ead2c _UIGestureRecognizerSendActions + 124
9 UIKit 0x379b23d8 -[UIGestureRecognizer _updateGestureWithEvent:] + 388
10 UIKit 0x37b9f474 ...
I work for Shinobi and we've been investigating this - it's partly due to Apple's map code keeping hold of our GL-Context. As a temporary workaround, you can create a subclass of a ShinobiChart and nil-out the GL context in the chart's dealloc method, like so:
- (void) dealloc {
[super dealloc];
[EAGLContext setCurrentContext:nil]; // must be after dealloc
}
or if you're using ARC, (since sending dealloc is not allowed):
#import <ShinobiCharts/SChartCanvas.h>
#interface ShinobiChartGl : ShinobiChart
#end
#implementation ShinobiChartGl
- (void) dealloc
{
[self.canvas.glView removeFromSuperview];
self.canvas.glView = nil; // force glView dealloc
[EAGLContext setCurrentContext:nil];
}
#end
Hope this helps, but do contact us directly - we'll have a full fix out in our next release.
for those who did not work even tried [EAGLContext setCurrentContext:nil]; on dealloc, try this
dispatch_async(dispatch_get_main_queue(), ^{
[EAGLContext setCurrentContext:nil];
});
EAGLContext should be set on main thread.

What could cause -[NSPasteboard types] to crash?

One of our customers is seeing a crash like this sometimes when pasting:
0 com.apple.Foundation 0x9143bd1d readPointerAt + 9
1 com.apple.Foundation 0x9153221f empty + 43
2 com.apple.Foundation 0x9145d41f dealloc + 21
3 com.apple.Foundation 0x9145d3ce -[NSConcreteMapTable dealloc] + 35
4 com.apple.AppKit 0x9092aa5d -[_NSPasteboardOwnersCollection dealloc] + 45
5 com.apple.AppKit 0x905cdb8f _NSPasteboardReportChangedOwner + 66
6 com.apple.AppKit 0x905cd4aa -[NSPasteboard _updateTypeCacheIfNeeded] + 51
7 com.apple.AppKit 0x905cd361 -[NSPasteboard _typesAtIndex:usesPboardTypes:] + 52
8 com.apple.AppKit 0x905cd327 -[NSPasteboard types] + 50
Does anyone have any idea what could cause this?
The pasteboard object is valid as far as I can tell but then crashes internally.
I think this is generally when pasting from another app, is it possible the other app is mismanaging its ownership of the pasteboard?
Further information from Does NSPasteboard retain owner objects? says that yes, the pasteboard retains the owners passed to it. Therefore, this crash must be either:
An over-release in my code. This causes an object to be deallocated while the pasteboard still holds a reference to it. I think this unlikely as you'd expect the problem to show up independent of the pasteboard, and I've not seen a single crash (report) to suggest that.
Something in the way NSPasteboard manages cross-application pastes is going wrong and crashing. Anyone encountered something like that or know what could cause it?
That appears to be when disposing of information about the previous owner (before the current owner as set by the user's most recent copy). Perhaps that's you? Check your copying code.
Also run your app under the Zombies instrument, if you haven't already.
If you accept a drop from a dragging paste and do the actual work asynchronously in another thread, you should retain the pasteboard itself, or otherwise, it might be deallocated when the function in the main thread returns.
It can probably happen in the dragging source side.
For example:
- (BOOL) outlineView:(NSOutlineView*)inOutlineView acceptDrop:(id<NSDraggingInfo>)inInfo item:(id)inItem childIndex:(NSInteger)inIndex
{
NSPasteboard* pboard = [[inInfo draggingPasteboard] retain]; // This is necessary!
BOOL result = YES;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^()
{
// Do the real work hear:
NSLog(#"types = %#", [pboard types]);
[pboard release];
});
return result;
}

Resources