Recover from C++ exceptions
Recover from C++ exceptions so that PSP does not think ASIO is running. Fixes a segfault when ASIO fails on internal invariant violation in runUntil() with m_current == nullptr.
Esse commit está contido em:
@@ -96,6 +96,10 @@ void AsioContext::runUntil(c_WaitableWaitHandle* wait_handle) {
|
||||
auto session = AsioSession::Get();
|
||||
uint8_t check_ete_counter = 0;
|
||||
|
||||
if (!session->hasAbruptInterruptException()) {
|
||||
session->initAbruptInterruptException();
|
||||
}
|
||||
|
||||
while (!wait_handle->isFinished()) {
|
||||
// process ready external thread events once per 256 other events
|
||||
// (when 8-bit check_ete_counter overflows)
|
||||
@@ -113,9 +117,12 @@ void AsioContext::runUntil(c_WaitableWaitHandle* wait_handle) {
|
||||
auto current = m_runnableQueue.front();
|
||||
m_runnableQueue.pop();
|
||||
m_current = current;
|
||||
auto exit_guard = folly::makeGuard([&] {
|
||||
m_current = nullptr;
|
||||
decRefObj(current);
|
||||
});
|
||||
|
||||
m_current->run();
|
||||
m_current = nullptr;
|
||||
decRefObj(current);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -118,6 +118,12 @@ void AsioSession::enqueueExternalThreadEvent(c_ExternalThreadEventWaitHandle* wa
|
||||
}
|
||||
}
|
||||
|
||||
void AsioSession::initAbruptInterruptException() {
|
||||
assert(!hasAbruptInterruptException());
|
||||
m_abruptInterruptException = SystemLib::AllocInvalidOperationExceptionObject(
|
||||
"The request was abruptly interrupted.");
|
||||
}
|
||||
|
||||
void AsioSession::onFailed(CObjRef exception) {
|
||||
if (m_onFailedCallback.get()) {
|
||||
try {
|
||||
|
||||
@@ -83,6 +83,17 @@ class AsioSession {
|
||||
c_ExternalThreadEventWaitHandle* waitForExternalThreadEvents();
|
||||
void enqueueExternalThreadEvent(c_ExternalThreadEventWaitHandle* wait_handle);
|
||||
|
||||
// abrupt interrupt exception
|
||||
CObjRef getAbruptInterruptException() {
|
||||
return m_abruptInterruptException;
|
||||
}
|
||||
|
||||
bool hasAbruptInterruptException() {
|
||||
return m_abruptInterruptException.get();
|
||||
}
|
||||
|
||||
void initAbruptInterruptException();
|
||||
|
||||
// callback: on failed
|
||||
void setOnFailedCallback(ObjectData* on_failed_callback) {
|
||||
assert(!on_failed_callback || on_failed_callback->instanceof(c_Closure::s_cls));
|
||||
@@ -162,6 +173,8 @@ class AsioSession {
|
||||
std::mutex m_readyExternalThreadEventsMutex;
|
||||
std::condition_variable m_readyExternalThreadEventsCondition;
|
||||
|
||||
Object m_abruptInterruptException;
|
||||
|
||||
Object m_onContinuationCreateCallback;
|
||||
Object m_onContinuationYieldCallback;
|
||||
Object m_onContinuationSuccessCallback;
|
||||
|
||||
@@ -192,6 +192,10 @@ void c_ContinuationWaitHandle::run() {
|
||||
} catch (const Object& exception) {
|
||||
// process exception thrown by generator or blockOn cycle detection
|
||||
markAsFailed(exception);
|
||||
} catch (...) {
|
||||
// process C++ exception
|
||||
markAsFailed(AsioSession::Get()->getAbruptInterruptException());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -140,25 +140,17 @@ void c_WaitableWaitHandle::join() {
|
||||
|
||||
// enter new asio context and set up guard that will exit once we are done
|
||||
session->enterContext();
|
||||
auto exit_guard = folly::makeGuard([&] { session->exitContext(); });
|
||||
|
||||
assert(session->isInContext());
|
||||
assert(!session->getCurrentContext()->isRunning());
|
||||
|
||||
try {
|
||||
// import this wait handle to the newly created context
|
||||
// throws if cross-context cycle found
|
||||
enterContext(session->getCurrentContextIdx());
|
||||
|
||||
// run queues until we are finished
|
||||
session->getCurrentContext()->runUntil(this);
|
||||
} catch (const Object& exception) {
|
||||
// recover from PHP exceptions; HPHP internal exceptions are deliberately
|
||||
// ignored as there is no easy way to recover from them
|
||||
session->exitContext();
|
||||
throw;
|
||||
}
|
||||
session->exitContext();
|
||||
// import this wait handle to the newly created context
|
||||
// throws if cross-context cycle found
|
||||
enterContext(session->getCurrentContextIdx());
|
||||
|
||||
// run queues until we are finished
|
||||
session->getCurrentContext()->runUntil(this);
|
||||
assert(isFinished());
|
||||
}
|
||||
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário