ExceptionPorts::GetExceptionPorts(): don’t return ExceptionHandler

elements whose handler port would be MACH_PORT_NULL.

For most exception targets, *_get_exception_ports() will normally return
an exception port of MACH_PORT_NULL when no handler is registered.
However, as of Mac OS X 10.9, thread_get_exception_ports() will return
an empty list when no handler is registered for any exception type on a
thread.

Consequently, a caller would have to do additional processing to
determine whether a specific exception port is registered: an
unregistered port will either appear but have a handler port of
MACH_PORT_NULL, or it will not appear at all. This is confusing for
callers. The behaviors are unified, and when a handler port of
MACH_PORT_NULL is found, it will not be returned to the caller. This is
expected to be the simpler of the two possible behaviors for callers to
make use of.

The change in the kernel can be seen by comparing 10.8.5
xnu-2050.48.11/osfmk/kern/ipc_tt.c thread_get_exception_ports() to the
same function in 10.9.4 xnu-2422.110.17. The 10.9 version has a special
check for thread->exc_actions being NULL, which short-circuits the rest
of the function without returning any exception ports. In 10.8.5,
thread->exc_actions can never be NULL. This new check is only present
for thread targets, presumably because it’s very common for threads to
not have any exception ports set, and not having to initialize this data
is an optimization. Typical user-level tasks in Mac OS X always have at
least some exception ports set at the task level.

TEST=util_test ExceptionPorts.TaskAndThreadExceptionPorts
R=rsesek@chromium.org

Review URL: https://codereview.chromium.org/584223002
This commit is contained in:
Mark Mentovai 2014-09-22 13:07:43 -04:00
parent c93fcf8278
commit 51e696ade9
2 changed files with 13 additions and 7 deletions

View File

@ -99,12 +99,14 @@ bool ExceptionPorts::GetExceptionPorts(
handlers->clear();
for (mach_msg_type_number_t index = 0; index < handler_count; ++index) {
ExceptionHandler handler;
handler.mask = masks[index];
handler.port = ports[index];
handler.behavior = behaviors[index];
handler.flavor = flavors[index];
handlers->push_back(handler);
if (ports[index] != MACH_PORT_NULL) {
ExceptionHandler handler;
handler.mask = masks[index];
handler.port = ports[index];
handler.behavior = behaviors[index];
handler.flavor = flavors[index];
handlers->push_back(handler);
}
}
return true;

View File

@ -112,7 +112,11 @@ class ExceptionPorts {
//! \param[out] handlers The exception handlers registered for \a target_port
//! to handle exceptions indicated in \a mask. The caller must take
//! ownership of the \a port members of the returned ExceptionHandler
//! objects. On failure, this argument is untouched.
//! objects. If no execption port is registered for a bit in \a mask, \a
//! handlers will not contain an entry corresponding to that bit. This is
//! a departure from the `*_get_exception_ports()` functions, which may
//! return a handler whose port is set to `EXCEPTION_PORT_NULL` in this
//! case. On failure, this argument is untouched.
//!
//! \return `true` if `*_get_exception_ports()` returned `KERN_SUCCESS`, with
//! \a handlers set appropriately. `false` otherwise, with an appropriate