Fix an issue with fb_intercept
After my rewrite to use the FunctionnEnter hook to implement intercept, there was a potential problem. If an intercept handler was intercepted, and we hadn't yet jitted the prolog for the intercept handler, and we lost the race to jit it, and the intercept handler threw an exception, the unwinder could skip some c++ frames, and fail to unwind a re-entry. This was caused by attempting to emulate the previous intercept behavior, where the original function is not included in the backtrace. I don't think thats necessary; for one thing, the intercept handler has always appeared in the backtrace, even though its (generally) not the replacement function, but a function that forwards to the replacement function. So this diff just leaves the original function's fraem in place. If the backtraces *do* turn out to be problematic, I'll fix it later in debugBacktrace.
Esse commit está contido em:
@@ -139,45 +139,40 @@ bool EventHook::RunInterceptHandler(ActRec* ar) {
|
||||
|
||||
PC savePc = g_vmContext->m_pc;
|
||||
|
||||
Offset pcOff;
|
||||
ActRec* outer = g_vmContext->getPrevVMState(ar, &pcOff);
|
||||
assert(outer);
|
||||
g_vmContext->m_fp = outer;
|
||||
g_vmContext->m_pc = outer->m_func->unit()->at(pcOff);
|
||||
Variant doneFlag = true;
|
||||
Variant called_on;
|
||||
|
||||
try {
|
||||
Variant doneFlag = true;
|
||||
Variant called_on;
|
||||
|
||||
if (ar->hasThis()) {
|
||||
called_on = Variant(ar->getThis());
|
||||
} else if (ar->hasClass()) {
|
||||
// For static methods, give handler the name of called class
|
||||
called_on = Variant(const_cast<StringData*>(ar->getClass()->name()));
|
||||
}
|
||||
Array intArgs =
|
||||
CREATE_VECTOR5(ar->m_func->fullNameRef(),
|
||||
called_on,
|
||||
get_frame_args_with_ref(ar),
|
||||
h->asCArrRef()[1],
|
||||
ref(doneFlag));
|
||||
|
||||
Variant ret = vm_call_user_func(h->asCArrRef()[0], intArgs);
|
||||
if (doneFlag.toBoolean()) {
|
||||
frame_free_locals_inl_no_hook<true>(ar, ar->m_func->numLocals());
|
||||
Stack& stack = g_vmContext->getStack();
|
||||
stack.top() = (Cell*)(ar + 1);
|
||||
tvDup(ret.asTypedValue(), stack.allocTV());
|
||||
return false;
|
||||
}
|
||||
g_vmContext->m_fp = ar;
|
||||
g_vmContext->m_pc = savePc;
|
||||
} catch (...) {
|
||||
g_vmContext->m_fp = ar;
|
||||
g_vmContext->m_pc = savePc;
|
||||
g_vmContext->m_stack.top() = Stack::frameStackBase(ar);
|
||||
throw;
|
||||
if (ar->hasThis()) {
|
||||
called_on = Variant(ar->getThis());
|
||||
} else if (ar->hasClass()) {
|
||||
// For static methods, give handler the name of called class
|
||||
called_on = Variant(const_cast<StringData*>(ar->getClass()->name()));
|
||||
}
|
||||
Array intArgs =
|
||||
CREATE_VECTOR5(ar->m_func->fullNameRef(),
|
||||
called_on,
|
||||
get_frame_args_with_ref(ar),
|
||||
h->asCArrRef()[1],
|
||||
ref(doneFlag));
|
||||
|
||||
Variant ret = vm_call_user_func(h->asCArrRef()[0], intArgs);
|
||||
if (doneFlag.toBoolean()) {
|
||||
Offset pcOff;
|
||||
ActRec* outer = g_vmContext->getPrevVMState(ar, &pcOff);
|
||||
assert(outer);
|
||||
|
||||
frame_free_locals_inl_no_hook<true>(ar, ar->m_func->numLocals());
|
||||
Stack& stack = g_vmContext->getStack();
|
||||
stack.top() = (Cell*)(ar + 1);
|
||||
tvDup(ret.asTypedValue(), stack.allocTV());
|
||||
|
||||
g_vmContext->m_fp = outer;
|
||||
g_vmContext->m_pc = outer->m_func->unit()->at(pcOff);
|
||||
|
||||
return false;
|
||||
}
|
||||
g_vmContext->m_fp = ar;
|
||||
g_vmContext->m_pc = savePc;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -149,7 +149,13 @@ asm(
|
||||
// fcallHelper, and then push it back from r15 + m_savedRip after
|
||||
// fcallHelper returns in case it has changed it.
|
||||
"1: pop 0x8(%r15)\n"
|
||||
// There is a brief span from enterTCAtProlog until the function
|
||||
// is entered where rbp is *below* the new actrec, and is missing
|
||||
// a number of c++ frames. The new actrec is linked onto the c++
|
||||
// frames, however, so switch it into rbp in case fcallHelper throws.
|
||||
"xchg %r15,%rbp\n"
|
||||
"call fcallHelper\n"
|
||||
"xchg %r15,%rbp\n"
|
||||
"push 0x8(%r15)\n"
|
||||
"jmp *%rax\n"
|
||||
"ud2\n"
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário