dyld::halt() EXC_CRASH exceptions arrive with a corpse task port despite not being EXC_CORPSE_NOTIFY

Originator:mark
Number:rdar://29079442 Date Originated:2016-11-02
Status:Closed Resolved:Behaves correctly
Product:macOS Product Version:10.12.1 16B2657
Classification:Other Bug Reproducible:Always
 
I compare task ports received in my catch_mach_exception_raise_state_identity() handlers against known task ports to know which task an exception message corresponds to.

In 10.12.1, the task ports received through this mechanism when dyld terminates are not proper task ports, but appear to be corpse tasks ports. A corpse task port has a different port name than the original task port from when it was a live task.

Corpse task ports are expected when receiving EXC_CORPSE_NOTIFY exceptions, but I am seeing this behavior even when receiving EXC_CRASH exceptions.

dyld switched to using the new abort_with_payload() mechanism from dyld::halt() in 10.12, but I did not experience this problem in 10.12. I only see it in 10.12.1.

Steps to Reproduce:
catch_dyld_crash.cc is a reduced testcase. It runs as a parent, which forks a child. The parent runs a Mach exception handler and waits for the child to crash. The child sets its task exception port for EXC_MASK_CRASH to the handler in the parent. The child then sets DYLD_INSERT_LIBRARIES to a nonexistent file and attempts to re-execute itself, triggering dyld to terminate via dyld::halt(). The EXC_CRASH exception message is delivered to the parent’s catch_exception_raise() function, with the |task| argument indicating which task crashed.

$ clang++ -g catch_dyld_crash.cc -o catch_dyld_crash
$ ./catch_dyld_crash

Expected Results:
Here’s 10.12 16A323. Previous OS versions are similar.

$ ./catch_dyld_crash
fork(): pid 655
child: pid 655
parent: child task 0xe03
dyld: could not load inserted library '/var/empty/NoDirectory/NoLibrary' because image not found

catch_exception_raise(): task 0xe03
catch_exception_raise(): pid 655
waitpid(): pid 655, stat 0x6
passed
$ 

Note “passed” at the bottom.

Actual Results:
Here’s 10.12.1 16B2657. It’s broken.

$ ./catch_dyld_crash
fork(): pid 3377
child: pid 3377
parent: child task 0xe03
dyld: could not load inserted library '/var/empty/NoDirectory/NoLibrary' because image not found

catch_exception_raise(): task 0x1003
catch_exception_raise(): pid 3377
waitpid(): pid 3377, stat 0x6
FAILED: child task 0xe03 != exception task 0x1003
$ 

It says FAILED at the bottom, because the live child task (0xe03) doesn’t match the task received by the EXC_CRASH handler (0x1003).

Version:
10.12.1 16B2657

Notes:
https://crashpad.chromium.org/bug/137

Configuration:
This bug occurs in 10.12.1 16B2657. It did not occur in 10.12 16A323 or previous OS versions.

Attachments:
'catch_dyld_crash.cc' was successfully uploaded. (https://bugs.chromium.org/p/crashpad/issues/attachment?aid=257618)

Comments

2017-03-17 21:51:45 UTC from Apple

Engineering has the following feedback for you:

It is not a corpse task port. Due to exec changes in 10.12.1, a new task and a new thread are created on exec which will have a new task port, hence after exec, the task port would not be same across exec, it will change, it its still a task port and not a corpse port.

Thank you for your feedback. Engineering has determined that this issue behaves as intended.

We are now closing this bug report.


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!