diff --git a/Builds/VisualStudio2015/RippleD.vcxproj b/Builds/VisualStudio2015/RippleD.vcxproj
index 25a6eab61..dfba11560 100644
--- a/Builds/VisualStudio2015/RippleD.vcxproj
+++ b/Builds/VisualStudio2015/RippleD.vcxproj
@@ -86,7 +86,7 @@
- HAVE_USLEEP=1;SOCI_CXX_C11=1;_WIN32_WINNT=0x6000;BOOST_NO_AUTO_PTR;DEBUG;DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER;NOMINMAX;NO_LOG_UNHANDLED_EXCEPTIONS;OPENSSL_NO_SSL2;WIN32_CONSOLE;_CRTDBG_MAP_ALLOC;_CRT_SECURE_NO_WARNINGS;_DEBUG;_SCL_SECURE_NO_WARNINGS;_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS;%(PreprocessorDefinitions)
+ HAVE_USLEEP=1;SOCI_CXX_C11=1;_WIN32_WINNT=0x6000;BOOST_NO_AUTO_PTR;DEBUG;DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER;NOMINMAX;OPENSSL_NO_SSL2;WIN32_CONSOLE;_CRTDBG_MAP_ALLOC;_CRT_SECURE_NO_WARNINGS;_DEBUG;_SCL_SECURE_NO_WARNINGS;_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS;%(PreprocessorDefinitions)
..\..\build\proto;..\..\src;..\..\src\beast;..\..\src\beast\extras;..\..\src\beast\include;..\..\src\protobuf\src;..\..\src\protobuf\vsprojects;..\..\src\soci\include;..\..\src\soci\src;%(AdditionalIncludeDirectories)
4800;4244;4267;4018
Async
@@ -123,7 +123,7 @@
- HAVE_USLEEP=1;SOCI_CXX_C11=1;_WIN32_WINNT=0x6000;BOOST_NO_AUTO_PTR;DEBUG;DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER;NOMINMAX;NO_LOG_UNHANDLED_EXCEPTIONS;OPENSSL_NO_SSL2;WIN32_CONSOLE;_CRTDBG_MAP_ALLOC;_CRT_SECURE_NO_WARNINGS;_DEBUG;_SCL_SECURE_NO_WARNINGS;_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS;%(PreprocessorDefinitions)
+ HAVE_USLEEP=1;SOCI_CXX_C11=1;_WIN32_WINNT=0x6000;BOOST_NO_AUTO_PTR;DEBUG;DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER;NOMINMAX;OPENSSL_NO_SSL2;WIN32_CONSOLE;_CRTDBG_MAP_ALLOC;_CRT_SECURE_NO_WARNINGS;_DEBUG;_SCL_SECURE_NO_WARNINGS;_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS;%(PreprocessorDefinitions)
..\..\build\proto;..\..\src;..\..\src\beast;..\..\src\beast\extras;..\..\src\beast\include;..\..\src\protobuf\src;..\..\src\protobuf\vsprojects;..\..\src\soci\include;..\..\src\soci\src;%(AdditionalIncludeDirectories)
4800;4244;4267;4018
Async
@@ -160,7 +160,7 @@
- HAVE_USLEEP=1;SOCI_CXX_C11=1;_WIN32_WINNT=0x6000;BOOST_NO_AUTO_PTR;DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER;NDEBUG;NOMINMAX;NO_LOG_UNHANDLED_EXCEPTIONS;OPENSSL_NO_SSL2;WIN32_CONSOLE;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS;%(PreprocessorDefinitions)
+ HAVE_USLEEP=1;SOCI_CXX_C11=1;_WIN32_WINNT=0x6000;BOOST_NO_AUTO_PTR;DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER;NDEBUG;NOMINMAX;OPENSSL_NO_SSL2;WIN32_CONSOLE;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS;%(PreprocessorDefinitions)
..\..\build\proto;..\..\src;..\..\src\beast;..\..\src\beast\extras;..\..\src\beast\include;..\..\src\protobuf\src;..\..\src\protobuf\vsprojects;..\..\src\soci\include;..\..\src\soci\src;%(AdditionalIncludeDirectories)
4800;4244;4267;4018
Async
@@ -195,7 +195,7 @@
- HAVE_USLEEP=1;SOCI_CXX_C11=1;_WIN32_WINNT=0x6000;BOOST_NO_AUTO_PTR;DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER;NDEBUG;NOMINMAX;NO_LOG_UNHANDLED_EXCEPTIONS;OPENSSL_NO_SSL2;WIN32_CONSOLE;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS;%(PreprocessorDefinitions)
+ HAVE_USLEEP=1;SOCI_CXX_C11=1;_WIN32_WINNT=0x6000;BOOST_NO_AUTO_PTR;DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER;NDEBUG;NOMINMAX;OPENSSL_NO_SSL2;WIN32_CONSOLE;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS;%(PreprocessorDefinitions)
..\..\build\proto;..\..\src;..\..\src\beast;..\..\src\beast\extras;..\..\src\beast\include;..\..\src\protobuf\src;..\..\src\protobuf\vsprojects;..\..\src\soci\include;..\..\src\soci\src;%(AdditionalIncludeDirectories)
4800;4244;4267;4018
Async
@@ -2016,6 +2016,12 @@
..\..\src\soci\src\core;..\..\src\sqlite;%(AdditionalIncludeDirectories)
..\..\src\soci\src\core;..\..\src\sqlite;%(AdditionalIncludeDirectories)
+
+ True
+ True
+ ..\..\src\soci\src\core;..\..\src\sqlite;%(AdditionalIncludeDirectories)
+ ..\..\src\soci\src\core;..\..\src\sqlite;%(AdditionalIncludeDirectories)
+
True
True
@@ -2072,12 +2078,6 @@
..\..\src\soci\src\core;..\..\src\sqlite;%(AdditionalIncludeDirectories)
..\..\src\soci\src\core;..\..\src\sqlite;%(AdditionalIncludeDirectories)
-
- True
- True
- ..\..\src\soci\src\core;..\..\src\sqlite;%(AdditionalIncludeDirectories)
- ..\..\src\soci\src\core;..\..\src\sqlite;%(AdditionalIncludeDirectories)
-
True
True
diff --git a/Builds/VisualStudio2015/RippleD.vcxproj.filters b/Builds/VisualStudio2015/RippleD.vcxproj.filters
index 8214e8077..cf260b47e 100644
--- a/Builds/VisualStudio2015/RippleD.vcxproj.filters
+++ b/Builds/VisualStudio2015/RippleD.vcxproj.filters
@@ -2553,6 +2553,9 @@
ripple\core\impl
+
+ ripple\core\impl
+
ripple\core\impl
@@ -2607,9 +2610,6 @@
ripple\core\tests
-
- ripple\core\tests
-
ripple\core\tests
diff --git a/SConstruct b/SConstruct
index ca5c0adba..3e581ecb3 100644
--- a/SConstruct
+++ b/SConstruct
@@ -365,7 +365,6 @@ def config_base(env):
,{'SOCI_CXX_C11' : '1'}
,'_SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS'
,'BOOST_NO_AUTO_PTR'
- ,'NO_LOG_UNHANDLED_EXCEPTIONS'
])
if Beast.system.windows:
@@ -385,6 +384,7 @@ def config_base(env):
openssl = os.path.join(OSX_OPENSSL_ROOT, most_recent)
env.Prepend(CPPPATH='%s/include' % openssl)
env.Prepend(LIBPATH=['%s/lib' % openssl])
+ env.Append(CPPDEFINES=['NO_LOG_UNHANDLED_EXCEPTIONS'])
# handle command-line arguments
profile_jemalloc = ARGUMENTS.get('profile-jemalloc')
diff --git a/src/ripple/app/main/Main.cpp b/src/ripple/app/main/Main.cpp
index fcd048394..0df70a6f8 100644
--- a/src/ripple/app/main/Main.cpp
+++ b/src/ripple/app/main/Main.cpp
@@ -28,6 +28,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -45,6 +46,7 @@
#include
#include
+
#if defined(BEAST_LINUX) || defined(BEAST_MAC) || defined(BEAST_BSD)
#include
#endif
@@ -452,7 +454,8 @@ int run (int argc, char** argv)
app->doStart();
// Block until we get a stop RPC.
- app->run();
+ ripple::threadEntry (
+ app.get(), &Application::run, "Main::run()");
// Try to write out some entropy to use the next time we start.
auto entropy = getEntropyFile (app->config());
@@ -517,6 +520,9 @@ int main (int argc, char** argv)
#endif
atexit(&google::protobuf::ShutdownProtobufLibrary);
+#ifndef NO_LOG_UNHANDLED_EXCEPTIONS
+ std::set_terminate(ripple::terminateHandler);
+#endif
auto const result (ripple::run (argc, argv));
diff --git a/src/ripple/basics/contract.h b/src/ripple/basics/contract.h
index 386aff65b..b2f481fdb 100644
--- a/src/ripple/basics/contract.h
+++ b/src/ripple/basics/contract.h
@@ -20,6 +20,7 @@
#ifndef RIPPLE_BASICS_CONTRACT_H_INCLUDED
#define RIPPLE_BASICS_CONTRACT_H_INCLUDED
+#include
#include
#include
#include
@@ -62,7 +63,8 @@ Throw (Args&&... args)
"Exception must derive from std::exception.");
E e(std::forward(args)...);
- LogThrow (std::string("Throwing exception: ") + e.what());
+ LogThrow (std::string("Throwing exception of type " +
+ beast::type_name() +": ") + e.what());
throw e;
}
diff --git a/src/ripple/core/ThreadEntry.h b/src/ripple/core/ThreadEntry.h
index f6108f9cc..1722218d4 100644
--- a/src/ripple/core/ThreadEntry.h
+++ b/src/ripple/core/ThreadEntry.h
@@ -20,35 +20,35 @@
#ifndef RIPPLE_CORE_THREAD_ENTRY_H_INCLUDED
#define RIPPLE_CORE_THREAD_ENTRY_H_INCLUDED
-#include
-#include // forced_unwind exception
-#include
-#include
-#include
#include
-#include
namespace ripple
{
+
+#ifndef NO_LOG_UNHANDLED_EXCEPTIONS
+namespace detail
+{
+void setThreadName(std::string name);
+}
+
+void terminateHandler();
+#endif
+
/**
Report uncaught exceptions to DebugLog and cerr
-Catch all exceptions that escape the called function. Report as much
-information as can be extracted from the exception to both the DebugLog
-and cerr.
+The actual reporting occurs in a terminate handler. This function
+stores information about which thread is running in thread local
+storage. That way the terminate handler can report not just the
+exception, but also the thread the exception was thrown in.
The idea is to use this routine at the top of a thread, since on
many platforms the stack trace for an uncaught exception on a thread
is almost useless.
For those platforms where the stack trace from an uncaught exception is
-useful (e.g., OS X) this routine is a no-op. That way a catch will not
-interfere with the stack trace showing the real source of the uncaught
-exception.
-
-Note that any extra information is passed using a lambda because we only
-want to do the work of building the string in the unlikely event of an
-uncaught exception. The lambda is only called in the error case.
+useful (e.g., OS X) this routine is turned into a no-op (because the
+preprocessor symbol NO_LOG_UNHANDLED_EXCEPTIONS is defined).
Usage example
@@ -87,65 +87,15 @@ int main ()
@param t Pointer to object to call.
@param threadTop Pointer to member function of t to call.
@param name Name of function to log.
-@param lamdba Optional lambda that returns additional text for the log.
*/
-template
-void threadEntry (
- T* t, R (T::*threadTop) (), char const* name, L&& lambda)
-{
- // Enforce that lambda takes no parameters and returns std::string.
- static_assert (
- std::is_convertible::value,
- "Last argument must be a lamdba taking no arguments "
- "and returning std::string.");
-
-#ifdef NO_LOG_UNHANDLED_EXCEPTIONS
- // Don't use a try block so we can get a good call stack.
- ((t)->*(threadTop)) ();
-#else
- // Local lambda for string formatting and re-throwing.
- auto logUncaughtException =
- [name, &lambda] (char const* exName)
- {
- std::stringstream ss;
- ss << "Unhandled exception in " << name
- << "; Exception: " << exName;
-
- std::string extra = lambda();
- if (! extra.empty())
- ss << "; " << extra;
-
- JLOG(debugLog().fatal()) << ss.str();
- std::cerr << ss.str() << std::endl;
- throw;
- };
-
- try
- {
- // Call passed in member function.
- ((t)->*(threadTop)) ();
- }
- catch (std::exception const& ex)
- {
- logUncaughtException (ex.what());
- }
- catch (boost::coroutines::detail::forced_unwind const&)
- {
- logUncaughtException ("forced_unwind");
- }
- catch (...)
- {
- logUncaughtException ("unknown exception type");
- }
-#endif // NO_LOG_UNHANDLED_EXCEPTIONS else
-}
-
-// Handle the common case where there is no additional local information.
template
-inline void threadEntry (
- T* t, R (T::*threadTop) (), char const* name)
+void threadEntry (
+ T* t, R (T::*threadTop) (), std::string name)
{
- threadEntry (t, threadTop, name, []{ return std::string(); });
+#ifndef NO_LOG_UNHANDLED_EXCEPTIONS
+ detail::setThreadName (std::move(name));
+#endif
+ ((t)->*(threadTop)) ();
}
} // namespace ripple
diff --git a/src/ripple/core/impl/Job.cpp b/src/ripple/core/impl/Job.cpp
index 5102d9078..3fa158304 100644
--- a/src/ripple/core/impl/Job.cpp
+++ b/src/ripple/core/impl/Job.cpp
@@ -77,15 +77,12 @@ bool Job::shouldCancel () const
void Job::doJob ()
{
- threadEntry (this, &Job::doJobImpl, "Job::doJob()",
- [this] ()
- {
- std::stringstream ss;
- ss << "Job name: " << this->mName
- << "; Job type: " << this->mType
- << "; Job info: " << this->mJob.target_type().name();
- return ss.str();
- });
+ std::stringstream ss;
+ ss << "Job::doJob(); Job name: "
+ << mName << "; Job type: " << mType
+ << "; Job info: " << mJob.target_type ().name ();
+
+ threadEntry (this, &Job::doJobImpl, ss.str());
}
void Job::rename (std::string const& newName)
diff --git a/src/ripple/core/impl/ThreadEntry.cpp b/src/ripple/core/impl/ThreadEntry.cpp
new file mode 100644
index 000000000..1649094de
--- /dev/null
+++ b/src/ripple/core/impl/ThreadEntry.cpp
@@ -0,0 +1,71 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of rippled: https://github.com/ripple/rippled
+ Copyright (c) 2012, 2013 Ripple Labs Inc.
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+namespace ripple {
+
+#ifndef NO_LOG_UNHANDLED_EXCEPTIONS
+namespace detail {
+thread_local
+std::string threadName;
+
+void setThreadName(std::string name)
+{
+ threadName = std::move(name);
+}
+}
+
+void terminateHandler()
+{
+ if (std::current_exception())
+ {
+ try
+ {
+ throw;
+ }
+ catch (const std::exception& e)
+ {
+ std::cerr << detail::threadName << ": " << e.what () << '\n';
+ JLOG(debugLog().fatal())
+ << detail::threadName << ": " << e.what () << '\n';
+ }
+ catch (boost::coroutines::detail::forced_unwind const&)
+ {
+ std::cerr << detail::threadName << ": forced_unwind\n";
+ JLOG(debugLog().fatal())
+ << detail::threadName << ": forced_unwind\n";
+ }
+ catch (...)
+ {
+ std::cerr << detail::threadName << ": unknown exception\n";
+ JLOG (debugLog ().fatal ())
+ << detail::threadName << ": unknown exception\n";
+ }
+ }
+}
+#endif
+
+}
diff --git a/src/ripple/core/impl/Workers.cpp b/src/ripple/core/impl/Workers.cpp
index ce8270cf2..fed9dce79 100644
--- a/src/ripple/core/impl/Workers.cpp
+++ b/src/ripple/core/impl/Workers.cpp
@@ -160,10 +160,7 @@ void Workers::Worker::run ()
{
// Call runImpl() and report if any exceptions escape runImpl.
threadEntry (this, &Workers::Worker::runImpl,
- "Workers::Worker::run()", [this] ()
- {
- return "Thread: " + Thread::getThreadName();
- });
+ "Workers::Worker::run(); Thread: " + Thread::getThreadName());
}
void Workers::Worker::runImpl ()
diff --git a/src/ripple/core/tests/ReportUncaughtException.test.cpp b/src/ripple/core/tests/ReportUncaughtException.test.cpp
deleted file mode 100644
index 744259eb9..000000000
--- a/src/ripple/core/tests/ReportUncaughtException.test.cpp
+++ /dev/null
@@ -1,169 +0,0 @@
-//------------------------------------------------------------------------------
-/*
- This file is part of rippled: https://github.com/ripple/rippled
- Copyright (c) 2016 Ripple Labs Inc.
-
- Permission to use, copy, modify, and/or distribute this software for any
- purpose with or without fee is hereby granted, provided that the above
- copyright notice and this permission notice appear in all copies.
-
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-*/
-//==============================================================================
-
-#include
-
-#include
-#include
-#include
-
-namespace ripple {
-
-// threadEntry is disabled if NO_LOG_UNHANDLED_EXCEPTIONS is defined.
-#ifndef NO_LOG_UNHANDLED_EXCEPTIONS
-
-class ReportUncaughtException_test : public TestSuite
-{
-public:
- class TestSink : public beast::Journal::Sink
- {
- std::stringstream ss_;
-
- public:
- TestSink()
- : Sink (beast::severities::kFatal, false)
- {
- }
-
- std::string getText() const
- {
- return ss_.str();
- }
-
- void reset()
- {
- ss_.str("");
- }
-
- void
- write (beast::severities::Severity level, std::string const& s) override
- {
- if (level >= threshold())
- ss_ << s;
- }
- };
-
- class ExceptionGen
- {
- public:
- // A place to keep methods that throw.
- void dontThrow()
- {
- return;
- }
-
- void throwStdExcept()
- {
- throw std::logic_error ("logic_error");
- }
-
- void throwForcedUnwind()
- {
- throw boost::coroutines::detail::forced_unwind ();
- }
-
- void throwWeird()
- {
- throw std::string ("Pretty unusual...");
- }
- };
-
- void test ()
- {
- // Install our own debug Sink so we can see what gets written.
- // Retain the old Sink so we can put it back.
- auto testSink = std::make_unique();
- TestSink& sinkRef = *testSink;
- std::unique_ptr oldSink =
- setDebugLogSink (std::move (testSink));
-
- ExceptionGen exGen;
-
- // Make sure nothing gets logged if there's no exception.
- threadEntry (&exGen, &ExceptionGen::dontThrow, "noThrow");
- expect (sinkRef.getText() == "");
- sinkRef.reset();
-
- threadEntry (&exGen, &ExceptionGen::dontThrow, "noThrow",
- [] { return "Just noise"; });
-
- expect (sinkRef.getText() == "");
- sinkRef.reset();
-
- using PExGenMemFn = void (ExceptionGen::*) ();
- auto testCase = [this, &exGen, &sinkRef] (
- PExGenMemFn call, char const* description)
- {
- std::string want = std::string ("Unhandled exception in "
- "testFn; Exception: ") + description;
-
- // Test the case without the closing lambda.
- bool gotException = false;
- try
- {
- threadEntry (&exGen, call, "testFn");
- }
- catch (...)
- {
- gotException = true;
- }
- expect (gotException == true);
- expect (sinkRef.getText() == want);
- sinkRef.reset();
-
- // Try the case with the closing lambda.
- gotException = false;
- try
- {
- threadEntry (&exGen, call, "testFn",
- []{ return "extra info"; });
- }
- catch (...)
- {
- gotException = true;
- }
- expect (gotException == true);
- expect (sinkRef.getText() == want + "; extra info");
- sinkRef.reset();
- };
-
- // Test logging for a stad::exception.
- testCase (&ExceptionGen::throwStdExcept, "logic_error");
-
- // Test logging for a forced_unwind.
- testCase (&ExceptionGen::throwForcedUnwind, "forced_unwind");
-
- // Test logging for none of the above.
- testCase (&ExceptionGen::throwWeird, "unknown exception type");
-
- // We're done with TestSink. Re-install the old Sink.
- setDebugLogSink (std::move (oldSink));
- }
-
- void run ()
- {
- test ();
- }
-};
-
-BEAST_DEFINE_TESTSUITE (ReportUncaughtException, core, ripple);
-
-#endif // NO_LOG_UNHANDLED_EXCEPTIONS
-
-} // ripple
diff --git a/src/ripple/unity/core.cpp b/src/ripple/unity/core.cpp
index a3259f992..11a708a35 100644
--- a/src/ripple/unity/core.cpp
+++ b/src/ripple/unity/core.cpp
@@ -30,11 +30,11 @@
#include
#include
#include
+#include
#include
#include
#include
#include
-#include
#include