[libc++abi] Simplify scan_eh_tab

1.
All `_URC_HANDLER_FOUND` return values need to set `landingPad`
and its value does not matter for `_URC_CONTINUE_UNWIND`. So we
can always set `landingPad` to unify code.

2.
For an exception specification (`ttypeIndex < 0`), we can check `_UA_FORCE_UNWIND` first.

3.
The so-called type 3 search (`actions & _UA_CLEANUP_PHASE && !(actions & _UA_HANDLER_FRAME)`)
is actually conceptually wrong.  For a catch handler or an unmatched dynamic
exception specification, `_UA_HANDLER_FOUND` should be returned immediately.  It
still appeared to work because the `ttypeIndex==0` case would return
`_UA_HANDLER_FOUND` at a later time.

This patch fixes the conceptual error and simplifies the code by handling type 3
the same way as type 2 (which is also what libsupc++ does).
The only difference between phase 1 and phase 2 is what to do with a cleanup
(`actionEntry==0`, or a `ttypeIndex==0` is found in the action record chain):
phase 1 returns `_URC_CONTINUE_UNWIND` while phase 2 returns `_URC_HANDLER_FOUND`.

Reviewed By: #libc_abi, compnerd

Differential Revision: https://reviews.llvm.org/D93190
This commit is contained in:
Fangrui Song 2021-01-21 15:19:22 -08:00
parent d38be2ba0e
commit cfe9ccbddd
1 changed files with 46 additions and 112 deletions

View File

@ -684,27 +684,21 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
return; return;
} }
landingPad = (uintptr_t)lpStart + landingPad; landingPad = (uintptr_t)lpStart + landingPad;
results.landingPad = landingPad;
#else // __USING_SJLJ_EXCEPTIONS__ #else // __USING_SJLJ_EXCEPTIONS__
++landingPad; ++landingPad;
#endif // __USING_SJLJ_EXCEPTIONS__ #endif // __USING_SJLJ_EXCEPTIONS__
if (actionEntry == 0) if (actionEntry == 0)
{ {
// Found a cleanup // Found a cleanup
// If this is a type 1 or type 2 search, there are no handlers results.reason = actions & _UA_SEARCH_PHASE
// If this is a type 3 search, you want to install the cleanup. ? _URC_CONTINUE_UNWIND
if ((actions & _UA_CLEANUP_PHASE) && !(actions & _UA_HANDLER_FRAME)) : _URC_HANDLER_FOUND;
{
results.ttypeIndex = 0; // Redundant but clarifying
results.landingPad = landingPad;
results.reason = _URC_HANDLER_FOUND;
return;
}
// No handler here
results.reason = _URC_CONTINUE_UNWIND;
return; return;
} }
// Convert 1-based byte offset into // Convert 1-based byte offset into
const uint8_t* action = actionTableStart + (actionEntry - 1); const uint8_t* action = actionTableStart + (actionEntry - 1);
bool hasCleanup = false;
// Scan action entries until you find a matching handler, cleanup, or the end of action list // Scan action entries until you find a matching handler, cleanup, or the end of action list
while (true) while (true)
{ {
@ -720,27 +714,17 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
native_exception, unwind_exception); native_exception, unwind_exception);
if (catchType == 0) if (catchType == 0)
{ {
// Found catch (...) catches everything, including foreign exceptions // Found catch (...) catches everything, including
// If this is a type 1 search save state and return _URC_HANDLER_FOUND // foreign exceptions. This is search phase, cleanup
// If this is a type 2 search save state and return _URC_HANDLER_FOUND // phase with foreign exception, or forced unwinding.
// If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1! assert(actions & (_UA_SEARCH_PHASE | _UA_HANDLER_FRAME |
// If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan _UA_FORCE_UNWIND));
if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME)) results.ttypeIndex = ttypeIndex;
{ results.actionRecord = actionRecord;
// Save state and return _URC_HANDLER_FOUND results.adjustedPtr =
results.ttypeIndex = ttypeIndex; get_thrown_object_ptr(unwind_exception);
results.actionRecord = actionRecord; results.reason = _URC_HANDLER_FOUND;
results.landingPad = landingPad; return;
results.adjustedPtr = get_thrown_object_ptr(unwind_exception);
results.reason = _URC_HANDLER_FOUND;
return;
}
else if (!(actions & _UA_FORCE_UNWIND))
{
// It looks like the exception table has changed
// on us. Likely stack corruption!
call_terminate(native_exception, unwind_exception);
}
} }
// Else this is a catch (T) clause and will never // Else this is a catch (T) clause and will never
// catch a foreign exception // catch a foreign exception
@ -757,36 +741,25 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
} }
if (catchType->can_catch(excpType, adjustedPtr)) if (catchType->can_catch(excpType, adjustedPtr))
{ {
// Found a matching handler // Found a matching handler. This is either search
// If this is a type 1 search save state and return _URC_HANDLER_FOUND // phase or forced unwinding.
// If this is a type 3 search and !_UA_FORCE_UNWIND, we should have found this in phase 1! assert(actions &
// If this is a type 3 search and _UA_FORCE_UNWIND, ignore handler and continue scan (_UA_SEARCH_PHASE | _UA_FORCE_UNWIND));
if (actions & _UA_SEARCH_PHASE) results.ttypeIndex = ttypeIndex;
{ results.actionRecord = actionRecord;
// Save state and return _URC_HANDLER_FOUND results.adjustedPtr = adjustedPtr;
results.ttypeIndex = ttypeIndex; results.reason = _URC_HANDLER_FOUND;
results.actionRecord = actionRecord; return;
results.landingPad = landingPad;
results.adjustedPtr = adjustedPtr;
results.reason = _URC_HANDLER_FOUND;
return;
}
else if (!(actions & _UA_FORCE_UNWIND))
{
// It looks like the exception table has changed
// on us. Likely stack corruption!
call_terminate(native_exception, unwind_exception);
}
} }
} }
// Scan next action ... // Scan next action ...
} }
else if (ttypeIndex < 0) else if (ttypeIndex < 0)
{ {
// Found an exception spec. If this is a foreign exception, // Found an exception specification.
// it is always caught. if (actions & _UA_FORCE_UNWIND) {
if (native_exception) // Skip if forced unwinding.
{ } else if (native_exception) {
// Does the exception spec catch this native exception? // Does the exception spec catch this native exception?
__cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1; __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1;
void* adjustedPtr = get_thrown_object_ptr(unwind_exception); void* adjustedPtr = get_thrown_object_ptr(unwind_exception);
@ -801,77 +774,38 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions,
ttypeEncoding, excpType, ttypeEncoding, excpType,
adjustedPtr, unwind_exception)) adjustedPtr, unwind_exception))
{ {
// native exception caught by exception spec // Native exception caught by exception
// If this is a type 1 search, save state and return _URC_HANDLER_FOUND // specification.
// If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1! assert(actions & _UA_SEARCH_PHASE);
// If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan
if (actions & _UA_SEARCH_PHASE)
{
// Save state and return _URC_HANDLER_FOUND
results.ttypeIndex = ttypeIndex;
results.actionRecord = actionRecord;
results.landingPad = landingPad;
results.adjustedPtr = adjustedPtr;
results.reason = _URC_HANDLER_FOUND;
return;
}
else if (!(actions & _UA_FORCE_UNWIND))
{
// It looks like the exception table has changed
// on us. Likely stack corruption!
call_terminate(native_exception, unwind_exception);
}
}
}
else
{
// foreign exception caught by exception spec
// If this is a type 1 search, save state and return _URC_HANDLER_FOUND
// If this is a type 2 search, save state and return _URC_HANDLER_FOUND
// If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1!
// If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan
if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME))
{
// Save state and return _URC_HANDLER_FOUND
results.ttypeIndex = ttypeIndex; results.ttypeIndex = ttypeIndex;
results.actionRecord = actionRecord; results.actionRecord = actionRecord;
results.landingPad = landingPad; results.adjustedPtr = adjustedPtr;
results.adjustedPtr = get_thrown_object_ptr(unwind_exception);
results.reason = _URC_HANDLER_FOUND; results.reason = _URC_HANDLER_FOUND;
return; return;
} }
else if (!(actions & _UA_FORCE_UNWIND)) } else {
{ // foreign exception caught by exception spec
// It looks like the exception table has changed
// on us. Likely stack corruption!
call_terminate(native_exception, unwind_exception);
}
}
// Scan next action ...
}
else // ttypeIndex == 0
{
// Found a cleanup
// If this is a type 1 search, ignore it and continue scan
// If this is a type 2 search, ignore it and continue scan
// If this is a type 3 search, save state and return _URC_HANDLER_FOUND
if ((actions & _UA_CLEANUP_PHASE) && !(actions & _UA_HANDLER_FRAME))
{
// Save state and return _URC_HANDLER_FOUND
results.ttypeIndex = ttypeIndex; results.ttypeIndex = ttypeIndex;
results.actionRecord = actionRecord; results.actionRecord = actionRecord;
results.landingPad = landingPad; results.adjustedPtr =
results.adjustedPtr = get_thrown_object_ptr(unwind_exception); get_thrown_object_ptr(unwind_exception);
results.reason = _URC_HANDLER_FOUND; results.reason = _URC_HANDLER_FOUND;
return; return;
} }
// Scan next action ...
} else {
hasCleanup = true;
} }
const uint8_t* temp = action; const uint8_t* temp = action;
int64_t actionOffset = readSLEB128(&temp); int64_t actionOffset = readSLEB128(&temp);
if (actionOffset == 0) if (actionOffset == 0)
{ {
// End of action list, no matching handler or cleanup found // End of action list. If this is phase 2 and we have found
results.reason = _URC_CONTINUE_UNWIND; // a cleanup (ttypeIndex=0), return _URC_HANDLER_FOUND;
// otherwise return _URC_CONTINUE_UNWIND.
results.reason = hasCleanup && actions & _UA_CLEANUP_PHASE
? _URC_HANDLER_FOUND
: _URC_CONTINUE_UNWIND;
return; return;
} }
// Go to next action // Go to next action