FileHandle(forWritingTo:) crash

I am having a rare crash when calling FileHandle(forWritingTo:) initializer with a file that does not exist.

In the documentation, I see that the expected behaviour is to return nil, but in my app, in rare cases I have a Crash.

My code that causes the crash is

if let handle = try? FileHandle(forWritingTo: logFile) {

Is it a known behaviour ? should I test if the file exist before calling FileHandle(forWritingTo:) ?

Answered by DTS Engineer in 862258022

I am having a rare crash when calling FileHandle(forWritingTo:) initializer with a file that does not exist.

In the documentation, I see that the expected behaviour is to return nil, but in my app, in rare cases I have a crash.

You're passing in a URL object that's already been released. The key clue is here:

Exception Subtype: KERN_INVALID_ADDRESS at 0x00000000deadbeef
Exception Codes: 0x0000000000000001, 0x00000000deadbeef

The address "0xdeadbeef" isn't accidental. It's a sentinel value that the system commonly uses when it wants to set a pointer to something that's recognizably "known" to be invalid. In the particular case, CFURL's* deallocate function sets the pointer that points to the actual string "bytes" to 0xdeadbeef just before it returns. Your app crashes like this the next time you try to use that URL object. In terms of tracking the issue down, testing with ASAN or the Zombie’s instrument are your best options.

*NSURL and CFURL share their underlying implementation.

As an aside, and not directly relevant to your crash, this "sentinel" pattern is common in system components which are widely used by the rest of the system (as well as developers). Their wide usage means they end up being implicated in a lot of crashes, so they end up going out of their way to try “marking" situations where they AREN'T responsible for the crash. There is actually another example of the same situation in the crash log you sent:

18 MyCoreModule	0x00000001053fd53c @objc MyDOperation.main() (in MyCoreModule) (/:0)
19 Foundation		0x0000000196337574 __NSOPERATION_IS_INVOKING_MAIN__ + 16 (NSOperation.m:2196)
20 Foundation		0x00000001963377fc -[NSOperation start] + 640 (NSOperation.m:1407)
21 Foundation		0x0000000196337bb0 __NSOPERATIONQUEUE_IS_STARTING_AN_OPERATION__ + 16 (NSOperation.m:2227)
22 Foundation		0x00000001963391cc __NSOQSchedule_f + 164 (NSOperation.m:2238)

Both of those "all caps" functions (NSOPERATIONQUEUE_IS_STARTING_AN_OPERATION & NSOPERATION_IS_INVOKING_MAIN) don't really "need" to be there. They're ONLY there so that the Foundation team can clearly identify the point where the framework left "their" code. The only thing that will crash either of those functions is bad data, which means it's not the framework’s fault.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Thank you for sharing your code. I noticed that there is only one line of code in your post. Could you please create a simple, focused project that demonstrates the issue? If the crash occurs, it should indicate that thread 7 is the problem on the path of the string. However, I am not sure about the value of the logFile. Additionally, you are using a try? block, but if you have a corresponding catch block, it should prevent the crash. It would be helpful to have a focused sample project that I can download and examine the exact issue.

If so, please share a link to your test project. That'll help us better understand what's going on. If you're not familiar with preparing a test project, take a look at Creating a test project.

Albert Pascual
  Worldwide Developer Relations.

I am having a rare crash when calling FileHandle(forWritingTo:) initializer with a file that does not exist.

In the documentation, I see that the expected behaviour is to return nil, but in my app, in rare cases I have a crash.

You're passing in a URL object that's already been released. The key clue is here:

Exception Subtype: KERN_INVALID_ADDRESS at 0x00000000deadbeef
Exception Codes: 0x0000000000000001, 0x00000000deadbeef

The address "0xdeadbeef" isn't accidental. It's a sentinel value that the system commonly uses when it wants to set a pointer to something that's recognizably "known" to be invalid. In the particular case, CFURL's* deallocate function sets the pointer that points to the actual string "bytes" to 0xdeadbeef just before it returns. Your app crashes like this the next time you try to use that URL object. In terms of tracking the issue down, testing with ASAN or the Zombie’s instrument are your best options.

*NSURL and CFURL share their underlying implementation.

As an aside, and not directly relevant to your crash, this "sentinel" pattern is common in system components which are widely used by the rest of the system (as well as developers). Their wide usage means they end up being implicated in a lot of crashes, so they end up going out of their way to try “marking" situations where they AREN'T responsible for the crash. There is actually another example of the same situation in the crash log you sent:

18 MyCoreModule	0x00000001053fd53c @objc MyDOperation.main() (in MyCoreModule) (/:0)
19 Foundation		0x0000000196337574 __NSOPERATION_IS_INVOKING_MAIN__ + 16 (NSOperation.m:2196)
20 Foundation		0x00000001963377fc -[NSOperation start] + 640 (NSOperation.m:1407)
21 Foundation		0x0000000196337bb0 __NSOPERATIONQUEUE_IS_STARTING_AN_OPERATION__ + 16 (NSOperation.m:2227)
22 Foundation		0x00000001963391cc __NSOQSchedule_f + 164 (NSOperation.m:2238)

Both of those "all caps" functions (NSOPERATIONQUEUE_IS_STARTING_AN_OPERATION & NSOPERATION_IS_INVOKING_MAIN) don't really "need" to be there. They're ONLY there so that the Foundation team can clearly identify the point where the framework left "their" code. The only thing that will crash either of those functions is bad data, which means it's not the framework’s fault.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

FileHandle(forWritingTo:) crash
 
 
Q