DRTVWR-558: Nail down LLDispatchListener exception handling
for exceptions other than those thrown by base-class LLEventDispatcher. Explain in LLDispatchListener Doxygen comments that for a request lacking a "reply" key, any exception is allowed to propagate because it's likely to reach the post() call that triggered the exception in the first place. For batch LLDispatchListener operations, catch not only LLEventDispatcher:: DispatchError exceptions but any std::exception, so we can collect them to report to the invoker. "Gotta catch 'em all!" Make LLLeap catch any std::exception thrown by processing a request from the plugin child process, log it and send a reply to the plugin. No plugin should be allowed to crash the viewer. (cherry picked from commit 94e10fd039b79f71ed8d7e10807b6e4eebd1928c)master
parent
c747ff0925
commit
2eb0ea9593
|
|
@ -848,10 +848,12 @@ void LLDispatchListener::call_map(const LLSD& reqmap, const LLSD& event) const
|
|||
// which request keys succeeded.
|
||||
result[name] = (*this)(name, args);
|
||||
}
|
||||
catch (const DispatchError& err)
|
||||
catch (const std::exception& err)
|
||||
{
|
||||
// collect message in 'errors'
|
||||
errors << delim << err.what();
|
||||
// Catch not only DispatchError, but any C++ exception thrown by
|
||||
// the target callable. Collect exception name and message in
|
||||
// 'errors'.
|
||||
errors << delim << LLError::Log::classname(err) << ": " << err.what();
|
||||
delim = "\n";
|
||||
}
|
||||
}
|
||||
|
|
@ -921,9 +923,12 @@ void LLDispatchListener::call_array(const LLSD& reqarray, const LLSD& event) con
|
|||
// With this form, capture return value even if undefined
|
||||
results.append((*this)(name, args));
|
||||
}
|
||||
catch (const DispatchError& err)
|
||||
catch (const std::exception& err)
|
||||
{
|
||||
error = err.what();
|
||||
// Catch not only DispatchError, but any C++ exception thrown by
|
||||
// the target callable. Report the exception class as well as the
|
||||
// error string.
|
||||
error = stringize(LLError::Log::classname(err), ": ", err.what());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -747,7 +747,10 @@ LLEventDispatcher::make_invoker(Method f, const InstanceGetter& getter)
|
|||
* "reply" is present, LLDispatchListener will send a response map to the
|
||||
* specified LLEventPump containing an "error" key whose value is the relevant
|
||||
* error message. If "reply" is not present, the DispatchError exception will
|
||||
* propagate.
|
||||
* propagate. Since LLDispatchListener bundles an LLEventStream, which
|
||||
* attempts the call immediately on receiving the post() call, there's a
|
||||
* reasonable chance that the exception will highlight the post() call that
|
||||
* triggered the error.
|
||||
*
|
||||
* If LLDispatchListener successfully calls the target callable, but no
|
||||
* "reply" key is present, any value returned by that callable is discarded.
|
||||
|
|
|
|||
|
|
@ -327,11 +327,28 @@ public:
|
|||
}
|
||||
else
|
||||
{
|
||||
// The LLSD object we got from our stream contains the keys we
|
||||
// need.
|
||||
LLEventPumps::instance().obtain(data["pump"]).post(data["data"]);
|
||||
// Block calls to this method; resetting mBlocker unblocks calls
|
||||
// to the other method.
|
||||
try
|
||||
{
|
||||
// The LLSD object we got from our stream contains the
|
||||
// keys we need.
|
||||
LLEventPumps::instance().obtain(data["pump"]).post(data["data"]);
|
||||
}
|
||||
catch (const std::exception& err)
|
||||
{
|
||||
// No plugin should be allowed to crash the viewer by
|
||||
// driving an exception -- intentionally or not.
|
||||
LOG_UNHANDLED_EXCEPTION(stringize("handling request ", data));
|
||||
// Whether or not the plugin added a "reply" key to the
|
||||
// request, send a reply. We happen to know who originated
|
||||
// this request, and the reply LLEventPump of interest.
|
||||
// Not our problem if the plugin ignores the reply event.
|
||||
data["reply"] = mReplyPump.getName();
|
||||
sendReply(llsd::map("error",
|
||||
stringize(LLError::Log::classname(err), ": ", err.what())),
|
||||
data);
|
||||
}
|
||||
// Block calls to this method; resetting mBlocker unblocks
|
||||
// calls to the other method.
|
||||
mBlocker.reset(new LLEventPump::Blocker(mStdoutDataConnection));
|
||||
// Go check for any more pending events in the buffer.
|
||||
if (childout.size())
|
||||
|
|
|
|||
Loading…
Reference in New Issue