Commit 4adc8128 authored by Kenton Varda's avatar Kenton Varda

When catching an unknown exception type, at least log the type.

parent b0775d6d
......@@ -22,6 +22,7 @@
#include "exception.h"
#include "debug.h"
#include <kj/compat/gtest.h>
#include <stdexcept>
namespace kj {
namespace _ { // private
......@@ -56,6 +57,36 @@ TEST(Exception, RunCatchingExceptions) {
}
}
#if !KJ_NO_EXCEPTIONS
TEST(Exception, RunCatchingExceptionsStdException) {
Maybe<Exception> e = kj::runCatchingExceptions([&]() {
throw std::logic_error("foo");
});
KJ_IF_MAYBE(ex, e) {
EXPECT_EQ("std::exception: foo", ex->getDescription());
} else {
ADD_FAILURE() << "Expected exception";
}
}
TEST(Exception, RunCatchingExceptionsOtherException) {
Maybe<Exception> e = kj::runCatchingExceptions([&]() {
throw 123;
});
KJ_IF_MAYBE(ex, e) {
#if __GNUC__ && !KJ_NO_RTTI
EXPECT_EQ("unknown non-KJ exception of type: int", ex->getDescription());
#else
EXPECT_EQ("unknown non-KJ exception", ex->getDescription());
#endif
} else {
ADD_FAILURE() << "Expected exception";
}
}
#endif
#if !KJ_NO_EXCEPTIONS
// We skip this test when exceptions are disabled because making it no-exceptions-safe defeats
// the purpose of the test: recoverable exceptions won't throw inside a destructor in the first
......
......@@ -35,6 +35,13 @@
#endif
#include "io.h"
#if !KJ_NO_RTTI
#include <typeinfo>
#if __GNUC__
#include <cxxabi.h>
#endif
#endif
#if (__linux__ && __GLIBC__ && !__UCLIBC__) || __APPLE__
#define KJ_HAS_BACKTRACE 1
#include <execinfo.h>
......@@ -918,6 +925,26 @@ void UnwindDetector::catchExceptionsAsSecondaryFaults(_::Runnable& runnable) con
runCatchingExceptions(runnable);
}
#if __GNUC__ && !KJ_NO_RTTI
static kj::String demangleTypeName(const char* name) {
if (name == nullptr) return kj::heapString("(nil)");
int status;
char* buf = abi::__cxa_demangle(name, nullptr, nullptr, &status);
kj::String result = kj::heapString(buf == nullptr ? name : buf);
free(buf);
return kj::mv(result);
}
kj::String getCaughtExceptionType() {
return demangleTypeName(abi::__cxa_current_exception_type()->name());
}
#else
kj::String getCaughtExceptionType() {
return kj::heapString("(unknown)");
}
#endif
namespace _ { // private
class RecoverableExceptionCatcher: public ExceptionCallback {
......@@ -960,8 +987,12 @@ Maybe<Exception> runCatchingExceptions(Runnable& runnable) noexcept {
return Exception(Exception::Type::FAILED,
"(unknown)", -1, str("std::exception: ", e.what()));
} catch (...) {
return Exception(Exception::Type::FAILED,
"(unknown)", -1, str("Unknown non-KJ exception."));
#if __GNUC__ && !KJ_NO_RTTI
return Exception(Exception::Type::FAILED, "(unknown)", -1, str(
"unknown non-KJ exception of type: ", getCaughtExceptionType()));
#else
return Exception(Exception::Type::FAILED, "(unknown)", -1, str("unknown non-KJ exception"));
#endif
}
#endif
}
......
......@@ -373,4 +373,10 @@ kj::StringPtr trimSourceFilename(kj::StringPtr filename);
// Given a source code file name, trim off noisy prefixes like "src/" or
// "/ekam-provider/canonical/".
kj::String getCaughtExceptionType();
// Utility function which attempts to return the human-readable type name of the exception
// currently being thrown. This can be called inside a catch block, including a catch (...) block,
// for the purpose of error logging. This function is best-effort; on some platforms it may simply
// return "(unknown)".
} // namespace kj
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment