Programmatically reading crash logs in Objective C in an OSX / cocoa app - objective-c

I want to be able to read a crash log and send it to my server. I've seen libraries that do this, and I'm actually basing my code on them -- except many of them seem out of date, which is why I believe I'm currently having a problem with OSX sandboxing.
There seem to be 2 parts to any generated crash log. In /Users/zane/Library/Containers/**[BUNDLE_ID]**/Data/Library/Application Support/CrashReporter there is a .plist with not much information. One thing it does contain, though, is a Path to ~/Library/Logs/DiagnosticReports/**FULL_CRASH_FILE**.crash
However, when I try to open this full path via [NSString stringWithContentsOfFile...] I get a read access error:
Error Domain=NSCocoaErrorDomain Code=257 "The file “Aftermath_2014-02-12-210934_inZania.crash” couldn’t be opened because you don’t have permission to view it." UserInfo=0x600000264700 {NSFilePath=/Users/zane/Library/Logs/DiagnosticReports/Aftermath_2014-02-12-210934_inZania.crash, NSUnderlyingError=0x600000246900 "The operation couldn’t be completed. Operation not permitted"}
I take it that this is a problem with entitlements/sandboxing. Is there any way I can gain access to this file, or otherwise get a full stack trace to send to my crash reporter?

You can check the permissions of the log file!! It may need root permissions to access!

Related

Reasons behind Cocoa error code NSFileWriteUnknownError

We are developing a document-based Objective-C project, using NSPersistentDocument and NSPersistentStore to save a unique binary file on disk. No autosave.
One customer has a recurring saving issue
The document "something.extension" could not be saved
that we cannot reproduce in our development setup. They can load their saved file without issue, but after a few changes the error pops up when trying to save. In our own setup, using the same build, the file opens and saves without issue.
The error is too vague for us to pinpoint the exact reason why their document would not save, but based on the very basic error message, we have realised the error raised is NSFileWriteUnknownError = 512.
In which situation would that error be raised? In which situation wouldn't the other, more specific error codes be applicable?
We build using SDK 10.14 and both us and the customer run on macOS Monterey 12.3.1
EDITED ON 09/08/22 - Added details based on Willeke's comments.
EDITED ON 17/08/22 - Underlying error
The error's userInfo comes with an underlying error message, which our customer could display. It states "No known persistent store for URL"

When programming, do you show all errors as message boxes or do you put them in a log file

I am trying to develop a standard when I code applications.
I was curious as to what other developers did when it comes to sql errors or general program errors. Do you output the error to the screen, write to a log file, or something else?
It really depends on the severity of the error.
Is it a show stopper?
Can the software automatically retry and get away with no message?
Can it be ignored?
You can log every exception, or just certain ones, or none. I have a custom Exception class which logs every exception created (of that type).
I have an unhandled exception handler which emails me when there is one.
I'd only send a message to the user when it will change the way the application works from the user's point of view.
Your question is a bit subjective and you would get opinion-based answers if the entire community bothered to answer.
If the error is relevant and important to the user (e.g.: invalid username/password) display it to the user using a message box.
If the error is relevant to the developer, or can be used in the debugging process, use a log or a console output.
The trick is to identify which and how the errors should be displayed to the user. You don't want to bombard the user with exceptions and complicated errors on which the user has no idea on how to act upon.

Understanding Objective-C throw call stack

A user has just submitted a bug report to me, saying that my app crashed. The user also attached a throw call stack.
The part which seems to have caused the problem is:
3 My App 0x000000010d005483 My App + 17539
Is there a way to translate that address and/or the + 17539 to a line number in my code?
Keep in mind, I wasn't able to reproduce the bug on my machine, so I can't just build it in debug mode.
Check out this Tech note from Apple.
... This trace is similar to what you would see when stopping execution in the debugger, except that you are not given the method or function names, known as symbols. Instead, you have hexadecimal addresses and executable code - your application or system frameworks - to which they refer. You need to map these addresses to symbols. Unlike crash logs from Mac OS X, iPhone OS logs do not contain symbol information when they're written out. You have to symbolicate iPhone OS logs before you can analyze them.
I've been using GDB to do manual symbolication. It'd be too cumbersome if you were doing it a lot, but the typical crash log doesn't have very many symbols, and I only need to symbolicate a crash log once in a while.
The procedure is as follows:
Put the .dSYM file for your app in the same folder as the .app.*
Open Terminal and cd to the folder from step 1.
Start your app up in GDB:
$ gdb YourApp.app/Contents/MacOS/YourApp
Set the print asm-demangle and print symbol-file options:
set print asm-demangle on
set print symbol-filename on
Use the p/a command to find the line numbers for each address in your stack trace:
p/a 0x000000010d005483
These instructions are from this page (apparently no longer online).
*Note that the .dSYM has a UDID tying it to the particular build it was created with. So, if you don't have the original .dSYM file, you're in trouble. Theoretically, you can't even just pull the same revision from source control and rebuild because this UDID will be different.

Mac App Store Reviewer says "It appears Kiwi fails codesign verification"

But it clearly does not fail on my system. The Verification test in XCode during the submission should (I assume) test this. And running codesign on the command line of the archived app results in:
/Users/iac/Library/Application Support/Developer/Shared/Archived Applications/272860A0-961E-47E7-B62F-0F7D373D938A.apparchive/Kiwi.app: valid on disk
/Users/iac/Library/Application Support/Developer/Shared/Archived Applications/272860A0-961E-47E7-B62F-0F7D373D938A.apparchive/Kiwi.app: satisfies its Designated Requirement
Anyone run into something like this before?
Thanks,
Isaiah
After a bit of back and forth the app was placed back "In Review" (without any change to the binary). It was then rejected again for another odd reason (No non-apple installers allowed) after which it was again placed back "In Review," (again without any changes to the binary).
After a few more emails it finally received a rejection that made sense: a few files in my resource folder had overly restrictive permissions.
So the answer is: double-check your file permissions or be doomed to weeks of confusion.
Isaiah

Is a file available to be opened?

Short version: I think I'm asking for a file too soon, but it's pretending like it's ready. Am I missing something?
Slightly longer version: I am writing files to disk. Before I do so, I have the user add some meta data, including the new file name. Once the user is done, the screen goes away and the program writes the file to disk. The user can then look at a list of files. That list is generated by reading the contents of a folder. The new file is in the list of files, but when I try to extract info from the file to display (e.g. file size) the program crashes. As best as I can tell, the crash occurs because, while the file is there in name, it's not available to be read. (By the way, these are small files - a few hundred k.)
First, is it possible that a file shows up in the directory but isn't all there yet?
a
And second, if so, how do I check to see if the file is ready to be read?
Thanks much.
UPDATE:
Thanks. I'll try to add more info. I'm recording an audio file with AVAudioRecorder. The init line is:
soundrecording = [[AVAudioRecorder alloc] initWithURL:url settings:recordSettings error:&error];
The program goes through it's UI updates and metering and all that. When the audio is stopped, I call:
[soundrecording stop];
and when everything else is updated and ready to move on, I call:
[soundrecording release];
soundrecording=NULL;
As far as I understand, this should take care of releasing the file, yes?
Thanks again.
The first thing I would do is confirm that you're right about the file not being ready yet. To do that, sleep your program for a second or two after writing and before reading. A few hundred KB should not take longer than that to be ready.
If it still fails, my guess is that you haven't closed the file handle that you used to write it. It may be unready for reading because the file system thinks you might keep writing.
Usually, the way to check to see if a file is ready is to attempt to open it. If that succeeds, you can read it. Or if it fails with an error, you can handle the error gracefully:
In a command-line utility, you might print the error and quit, and the user could try again.
If it's a background program that should not quit, like a server, you could log the error. You might also try again automatically after a delay. If it's a big deal kind of error, you might want to have the program email you about it.
In an GUI window app, you probably want to show an error dialog or panel, and then give the user an opportunity to retry.
Now that you have added sample code, I can say some more.
First, the class reference seems to say that the stop method will close the file. However it also seems to suggest that there is an underlying audio session going on, and possibly some conversion. I think I recall that the iPhone's Voice Notes app, which probably uses this API, has to do some work to compress a long recording after it's completed.
So I support your hunch. I think that your file may not be closed yet, but on another thread that is processing the recorded data into a proper format to save.
You probably want to set a NSTimer to attempt to open the file every second or so, so that your user interface can perk up when it's done. You probably want to show a "Please wait" sort of message in the meantime, or otherwise let the user know it's working.