Is this kind of crash report useless? - iphone

I tried use "PLCrashReport" to collect the crash info then make the app more stable, but turns out that the report is like this(dont even has a call stack,how am I suppose to use it?):
The "Exception:" part,Exception: (null): (null), which should be "exceptionName" and "exceptionReason", at most time are "null", dont know why, sometimes there will be a normal value but also I think not quite useful...
Crashed on 2009-11-13 23:43:04 +0800
- Signal SIGSEGV (code SEGV_ACCERR, address=0xffffffffc0f4186b)
Exception: (null): (null) - Thread 0:
Crashed: 1
Stack (54 frames):,\n 806128664,\n 807756495,\n 816280840,\n 816247
068,\n 817901396,\n 807756495,\n 816280840,\n 817911108,\n 816247068,\n 816285160,\n 816406620,\n 807756495,\n 806130012,\n 119241,\n 812165747,\n 812164839 ,\n 812379009,\n 818127880,\n 807885435,\n 807923065,\n 818122176,\n 818130772,\n 816625560,\n 816626608,\n 816627024,\n 816641892,\n 816651496,\n 816654628 ,\n 816654224,\n 146455,\n 807923363,\n 816119156,\n 816119004,\n 818227300,\n 807923363,\n 816119156,\n 816119004,\n 816524332,\n 816525956,\n 816521588,\n 816212028,\n 816151252,\n 816147980,\n 827758796,\n 827769116,\n 837343488,\n 821391952,\n 807840887,\n 807836793,\n 807834407,\n 827752032,\n 816118388,\n816157144,\n 20421

What's a stack trace?
Whenever one of your methods gets called, it puts this onto the stack. A stack trace is a way of finding out which class and method your app crashed in, which often narrows down the bug to a single line.
Of course to do this, the stack trace needs to be readable, rather than a whole load of hex numbers.
Check out atos.
To prevent this happening again, you could interpret this Call Stack using atos.
See the Stack Traces page of the Cocoa Dev wiki for a discussion and code on how to convert these numbers into meaningful methods.
You'll need to figure out a way of integrating this with the crash reporter. I use UKCrashReporter and I've modified Uli's code so that if there's an uncaught exception it adds the readable stack trace onto the crash report.
Code Sample
I've taken inspiration from the ESStackTrace class and here's what I do:
-(void)logAndSaveStackTrace {
NSString *stackTrace = [[self userInfo] objectForKey:NSStackTraceKey];
NSString *atosCommand;
if (stackTrace) {
// If the stack trace key is present, pull out the addresses and convert to method names using atos.
atosCommand = [NSString stringWithFormat:#"/usr/bin/atos -p %d %# | tail -n +3 | head -n +%d | c++filt | cat -n",
[[NSProcessInfo processInfo] processIdentifier],
stackTrace,
([[stackTrace componentsSeparatedByString:#" "] count] - 4)];
} else {
// If there isn't a stack trace key or it's nil, try and work out the stack using the internal callStackReturn addresses method.
NSArray *stackTraceArray = [self callStackReturnAddresses];
atosCommand = [NSString stringWithFormat:#"/usr/bin/atos -p %d %#",
[[NSProcessInfo processInfo] processIdentifier],
[stackTraceArray componentsJoinedByString:#" "]];
}
NSString *readableStackTrace = [ShellTask executeShellCommandSynchronously:atosCommand];
NSString *exceptionMessageForCrashReport = [NSString stringWithFormat:#"An exception of type %s occured.\n%s\nStack trace:\n%#",
[[self name] cStringUsingEncoding:NSUTF8StringEncoding],
[[self reason] cStringUsingEncoding:NSUTF8StringEncoding],
readableStackTrace];
[[NSUserDefaults standardUserDefaults] setObject:exceptionMessageForCrashReport forKey:#"uncaughtExceptionReport"];
[[NSUserDefaults standardUserDefaults] synchronize];
// Log the exception to the console too.
NSLog(#"%#", exceptionMessageForCrashReport);
}
Dependencies Ahoy!
Of course, one of the problems with this approach is that you're introducing a dependency on atos. I've been told that it's installed as standard on 10.5 and later, but this might be wrong. Eventually I'm going to make a little installer which adds atos if my app can't find it.

I haven't used it but I'm pretty sure you're not getting any detail because you had a segmentation fault that took out everything down to the registers. The PLCrashReport instance can't report because it died along with everything else.
The PLCrashReport instances runs within the Application itself so if the app goes down hard you won't get any detail.

Related

How to remove bytes from the end of NSMutableData object

I have a NSMutableData object that is giving me some trouble, I am trying to remove the last 6 bytes from the object like this
NSMutableData *reducedDataPacket = [[NSMutableData alloc] init];
reducedDataPacket = [myCompressedData copy];
NSRange range = NSMakeRange([reducedDataPacket length]-6, 6);
[reducedDataPacket replaceBytesInRange:range withBytes:NULL length:0];
However once the last line executes my app crashes and I am left with this error below.
-[NSConcreteData replaceBytesInRange:withBytes:length:]: unrecognized selector sent to instance 0x1f037870
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSConcreteData replaceBytesInRange:withBytes:length:]: unrecognized selector sent to instance 0x1f037870
I have never tried doing this before and have been going off other answeres supplied I have investigated, but I just cannot get this to work... any help would be greatly appreciated.
Your first line is useless because you then redefine reducedDataPacket in the second line, so that first line should be deleted. I'm guessing that myCompressedData is NSData rather than NSMutableData, so change that second line to :
NSMutableData *reducedDataPacket = [myCompressedData mutableCopy];
First you need a mutable instance, it isn't clear why you create one and then copy it. You should just do:
NSMutableData *reducedDataPacket = [myCompressedData mutableCopy];
Then you want to reduce the length, not try to fill part of the data with nothing:
[reducedDataPacket setLength:(reducedDataPacket.length - 6)];

Assertion Failure in Calculator Program

So I'm working on a simple calculator program to get used to cocoa and objective C. I've redone the whole thing multiple times and every time I finish coding, the first time i build it, it works fine, but every time after that the window wont launch and it gives me these errors:
2013-01-11 10:32:14.760 Visual Caluclator Fix[39892:403] *** Assertion failure in -[NSTextFieldCell _objectValue:forString:errorDescription:], /SourceCache/AppKit/AppKit-1138.47/AppKit.subproj/NSCell.m:1564
2013-01-11 10:32:14.762 Visual Caluclator Fix[39892:403] Ignoring exception raised in __-[NSPersistentUIManager restoreAllPersistentStateWithTalagentWindows:registeringAsReadyWhenDone:completionHandler:]_block_invoke_3: Invalid parameter not satisfying: aString != nil
I've concluded that the problem lies in my textEdited method, because when I comment the code inside of it out, the program has no issues running; however, I have no idea why this is, or why it would run the first time and not any subsequent times. When I put in an exception breakpoint, it points me to the one line in the updateUI method and the call to [self updateUI] in the textEdited method. The following code is the textEdited method and the other methods it references.(I'm fairly sure there's nothing wrong with the solve method because I used it in a command prompt calculator and it worked great. Also, I know this is a pretty convoluted way to program a calculator, with the strings and everything, but I was just trying to integrate the code I already had for the command prompt program into a cocoa program.)
In the AppDelegate class:
- (void)updateUI{
[self.calculationView setStringValue: self.calculation.calcString];//Exception breakpoint points here
}
- (IBAction)textEdited:(id)sender {
self.calculation.calcString = self.calculationView.stringValue;
[self.calculation solve];
[self updateUI];//Exception breakpoint points here
}
In the Calculation class:
- (NSString*)solve{
for (int i = 0; i < [self.calcString length]; i++) {
NSRange nextChar = NSMakeRange(i, 1);
if ([[self.calcString substringWithRange: nextChar] isEqualToString: #"*"]||
[[self.calcString substringWithRange: nextChar] isEqualToString: #"/"])
[self calcTerm: i];
}
for (int i = 0; i < [self.calcString length]; i++) {
NSRange nextChar = NSMakeRange(i, 1);
if ([[self.calcString substringWithRange: nextChar] isEqualToString: #"+"]||
[[self.calcString substringWithRange: nextChar] isEqualToString: #"-"])
[self calcTerm: i];
}
return self.calcString;
}
This might help with your problem:
http://www.raywenderlich.com/10505/my-app-crashed-now-what-part-2
The site explains how assertion errors work and demonstrate how you would fix an error like that.
It sounds to me like something in calcTerm: is setting calcString to nil. Thus, when you retrieve it later to set the field's string value to it, you end up setting the field's string value to nil, which it doesn't like.
You can check this by logging the value of calcString just before the end of solve. Then, start stringing up log statements and/or breakpoints in calcTerm: to find out how you're swapping out your string for nil.

ALAssetsLibrary enumerateGroupsWithTypes returns no data

I am using the AssetsLibrary framework to retrieve all asset groups in the iPhone. I have some code snippet like this:
NSMutableArray *groups = [[NSMutableArray alloc] initWithCapacity:5];
void (^groupEnumerator)(ALAssetsGroup*, BOOL*) = ^(ALAssetsGroup *group, BOOL *stop) {
if(group != nil) {
NSLog(#"Adding group %#", [group valueForProperty:ALAssetsGroupPropertyName]);
[groups addObject:group];
}
};
ALAssetsLibrary* library = [AssetsManager defaultAssetsLibrary];
[library enumerateGroupsWithTypes: ALAssetsGroupSavedPhotos
usingBlock:groupEnumerator
failureBlock:^(NSError * err) {NSLog(#"Erorr: %#", [err localizedDescription]);}];
And I found a weird behavior:
1) When I run my app in the iOS simulator (use command + R in Xcode), the groupEnumerator will be executed and group names will be printed in the console
2) I wrote some unit test for my app, when I run the unit test (use command + U in Xcode), which calls the above code snippet as it is called in my app, the groupEnumerator seems not get executed at all and none of the group name will be printed, and the failureBlock doesn't get called too and I don't get any error when running the tests but the group enumeration doesn't work as it does in the app.
I check Apple's documentation, and I know this method (enumerateGroupsWithTypes:usingBlock:failureBlock:) is asynchronous, however, even if I wait for a long time in my unit test, I don't see the groupEnumerator get executed.
I am testing against iOS 5.0 with Xcode 4.2.
Any help is appreciated. Thanks.
Stuck on this problem for several days, couldn't figure out the exact cause of this issue.
And instead of using OCUnit in Xcode 4, I had to switch to use gh-unit, which solves this issue actually. It seems related with the way Xcode 4 runs the test target.
http://gabriel.github.com/gh-unit

Crash log without crash?

Hey this may be a stupid question but I couldn't find the answer anywhere, apologies if the answer is easily found and if my research skills are pants.
anyway is it possible to generate a crash report when an app doesn't crash? so say if a user encounters a bug could there be an option to allow them to generate a crash report which can then be sent to me? also how would I go about doing this?
Thanks for any help :)
I have used it couple of times when I had to print stack trace:
+ (NSArray *)backtrace
{
void* callstack[128];
int frames = backtrace(callstack, 128);
char **strs = backtrace_symbols(callstack, frames);
int i;
NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames];
for (
i = UncaughtExceptionHandlerSkipAddressCount;
i < UncaughtExceptionHandlerSkipAddressCount +
UncaughtExceptionHandlerReportAddressCount;
i++)
{
[backtrace addObject:[NSString stringWithUTF8String:strs[i]]];
}
free(strs);
return backtrace;
}
"When an application crashes on the iPhone, it disappears without telling the user what happened. However, it is possible to add exception and signal handling to your applications so that an error message can be displayed to the user or you can save changes. It is even possible to try to recover from this situation without crashing at all."
Look at http://cocoawithlove.com/2010/05/handling-unhandled-exceptions-and.html
Here's what I use for my stacktraces:
NSArray *callStackArray = [exception callStackReturnAddresses];
int frameCount = [callStackArray count];
void *backtraceFrames[frameCount];
for (int i=0; i < frameCount; i++) {
backtraceFrames[i] = (void *)[[callStackArray objectAtIndex:i] unsignedIntegerValue];
}
char **strs = backtrace_symbols(backtraceFrames, frameCount);
NSMutableArray *backtraceArray = [NSMutableArray arrayWithCapacity:frameCount];
for (int i = 0; i < frameCount; i++) {
NSString *entry = [NSString stringWithUTF8String:strs[i]];
[backtraceArray addObject:entry];
}
free(strs);
You just have to make sure you don't do any harm to your app: http://landonf.bikemonkey.org/2011/09/14. You could also use PLCrashReporter to handle all your crashes or if you're lazy like me, use a service like Crittercism
I used to use backtrace_symbols for handling my crashes too, but then I found out that it could be dangerous since the method is not async-safe. I've since looked at a bunch of crash reporting solutions and went with Crittercism for my apps and it's been pretty sweet!
I suggest you check out TestFlight SDK released a few days ago. It has some awesome features like remote logging and even live crash reports.
For an ad hoc version, you could just call the function abort(), or throw and exception of some kind.
An App Store version will not be allowed to ship if it crashes at all during testing.

Parsing my flat-file on iPhone is a pain in the ***, please Help me out

I am programming an iPhone App which is supposed to parse a flat-file from the web, create managed objects from the flat-file and later on should display them in an UITableView.
There are no problems with the saving and the displaying, but I just can't get the hang of a good Parser.
Thats the file I want to parse: Flat-file
AS far as I know, I can't use the NSXMLParser for this task (because obviously there are no tags).
So I at first tried to programm a NSScanner which should get me the interesting properties --> didn't work out
Now I am using this method:
- (void) parseMemberDataWithURL: (NSString *)urlString
{
self.memberTempCounter = 1;
//Get data from web
self.downloadedText = [NSString stringWithContentsOfURL: [NSURL URLWithString: urlString] encoding:NSUTF8StringEncoding error:nil ];
memberArray = [downloadedText componentsSeparatedByString:#";"];
while (self.memberTempCounter<[memberArray count])
{
[[ExhibitorController sharedController] createExhibitorWithName:[memberArray objectAtIndex:self.memberTempCounter]
street:[memberArray objectAtIndex:self.memberTempCounter+2]
zip:[memberArray objectAtIndex:self.memberTempCounter+3]
city:[memberArray objectAtIndex:self.memberTempCounter+4]
email:[memberArray objectAtIndex:self.memberTempCounter+7]
phone:[memberArray objectAtIndex:self.memberTempCounter+5]
website:[memberArray objectAtIndex:self.memberTempCounter+8]
produktbereiche:[[memberArray objectAtIndex:self.memberTempCounter+9] componentsSeparatedByString:#","]];
self.memberTempCounter= self.memberTempCounter+13;
}
}
I am using the memberTempCounter to identify the property.
The problems are:
This only works out in like 3 of 4 times.1 of 4 times the App crashes and I have no Idea why...
The method has a performance like a 1962 VW Beetle. Parsing the whole chunk of data takes up to 3 Minutes on my iPhone 3G
Any Ideas or a simpler way to do this?
I would be really gratefull. Thanks in advance: -)
You might as well do all the parsing in the background, and then display as the information gets parsed.
As for memory issues, try doing temporary autorelease pools and release every 50 or so iterations through the loop.
int count = 0;
NSAutoreleasePool * loopPool = [[NSAutoreleasePool alloc] init];
while(someInsanelyLargeCondition){
// Do your stuff here
// .............
count++;
if (count > 50) {
count = 0;
[loopPool release];
loopPool = [[NSAutoreleasePool alloc] init];
}
}
Recursive-descent (LL1) parsers are pretty simple, light on memory, and for speed they go almost as fast as you can run a pointer through characters. Building your data structure would probably be the dominant time-taker.
I was finally able to fix my performance problem.
I have a method in another class, which ads Tags for the different Exhibitors. Therefore it first checks if the Tag already is stored in the database or else creates it.
With an growing Set of Tags in my database the search-process took longer and longer and this led to the long parsing time.
Anyone else having this problem: Take a look at the Performance Core Data Programming guide of apple in the "Implementing Find-or-Create Efficiently"-section:
http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/CoreData/Articles/cdImporting.html