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 @@ ...@@ -22,6 +22,7 @@
#include "exception.h" #include "exception.h"
#include "debug.h" #include "debug.h"
#include <kj/compat/gtest.h> #include <kj/compat/gtest.h>
#include <stdexcept>
namespace kj { namespace kj {
namespace _ { // private namespace _ { // private
...@@ -56,6 +57,36 @@ TEST(Exception, RunCatchingExceptions) { ...@@ -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 #if !KJ_NO_EXCEPTIONS
// We skip this test when exceptions are disabled because making it no-exceptions-safe defeats // 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 // the purpose of the test: recoverable exceptions won't throw inside a destructor in the first
......
...@@ -35,6 +35,13 @@ ...@@ -35,6 +35,13 @@
#endif #endif
#include "io.h" #include "io.h"
#if !KJ_NO_RTTI
#include <typeinfo>
#if __GNUC__
#include <cxxabi.h>
#endif
#endif
#if (__linux__ && __GLIBC__ && !__UCLIBC__) || __APPLE__ #if (__linux__ && __GLIBC__ && !__UCLIBC__) || __APPLE__
#define KJ_HAS_BACKTRACE 1 #define KJ_HAS_BACKTRACE 1
#include <execinfo.h> #include <execinfo.h>
...@@ -918,6 +925,26 @@ void UnwindDetector::catchExceptionsAsSecondaryFaults(_::Runnable& runnable) con ...@@ -918,6 +925,26 @@ void UnwindDetector::catchExceptionsAsSecondaryFaults(_::Runnable& runnable) con
runCatchingExceptions(runnable); 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 namespace _ { // private
class RecoverableExceptionCatcher: public ExceptionCallback { class RecoverableExceptionCatcher: public ExceptionCallback {
...@@ -960,8 +987,12 @@ Maybe<Exception> runCatchingExceptions(Runnable& runnable) noexcept { ...@@ -960,8 +987,12 @@ Maybe<Exception> runCatchingExceptions(Runnable& runnable) noexcept {
return Exception(Exception::Type::FAILED, return Exception(Exception::Type::FAILED,
"(unknown)", -1, str("std::exception: ", e.what())); "(unknown)", -1, str("std::exception: ", e.what()));
} catch (...) { } catch (...) {
return Exception(Exception::Type::FAILED, #if __GNUC__ && !KJ_NO_RTTI
"(unknown)", -1, str("Unknown non-KJ exception.")); 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 #endif
} }
......
...@@ -373,4 +373,10 @@ kj::StringPtr trimSourceFilename(kj::StringPtr filename); ...@@ -373,4 +373,10 @@ kj::StringPtr trimSourceFilename(kj::StringPtr filename);
// Given a source code file name, trim off noisy prefixes like "src/" or // Given a source code file name, trim off noisy prefixes like "src/" or
// "/ekam-provider/canonical/". // "/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 } // 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