From 4e94dfd4d9f30bfbe17987b3b98663187751ffcb Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 1 Oct 2018 05:51:21 +0200 Subject: [PATCH] FailureHandling: improved ZombieCheck now capturing the Zombie's ID ==> surprise, its ClassLock --- src/lib/depend.hpp | 2 +- src/lib/sync-classlock.hpp | 3 +- src/lib/zombie-check.hpp | 33 ++++++++- tests/25fundamental.tests | 5 ++ tests/basics/zombie-check-test.cpp | 88 ++++++++++++++++++++++++ wiki/thinkPad.ichthyo.mm | 105 +++++++++++++++++++++++++---- 6 files changed, 219 insertions(+), 17 deletions(-) create mode 100644 tests/basics/zombie-check-test.cpp diff --git a/src/lib/depend.hpp b/src/lib/depend.hpp index 3dff59462..2a3e1c910 100644 --- a/src/lib/depend.hpp +++ b/src/lib/depend.hpp @@ -141,7 +141,7 @@ namespace lib { Deleter deleter_; public: - ZombieCheck zombieCheck; + ZombieCheck zombieCheck{util::typeStr()}; DependencyFactory() = default; ~DependencyFactory() diff --git a/src/lib/sync-classlock.hpp b/src/lib/sync-classlock.hpp index 22acbaec8..abc581ce4 100644 --- a/src/lib/sync-classlock.hpp +++ b/src/lib/sync-classlock.hpp @@ -39,6 +39,7 @@ #include "lib/nobug-init.hpp" #include "lib/zombie-check.hpp" +#include "lib/meta/util.hpp" #include "lib/sync.hpp" @@ -72,7 +73,7 @@ namespace lib { getPerClassMonitor() { static PerClassMonitor classMonitor; - static ZombieCheck zombieCheck; + static ZombieCheck zombieCheck{util::typeStr(this)}; zombieCheck(); return classMonitor; diff --git a/src/lib/zombie-check.hpp b/src/lib/zombie-check.hpp index 5c19079a7..b4f005d7e 100644 --- a/src/lib/zombie-check.hpp +++ b/src/lib/zombie-check.hpp @@ -30,6 +30,7 @@ ** we may plant an automatic "zombie detector" to give a clear indication of ** such a policy violation (Lumiera forbids to use dependencies from dtors). ** + ** @see ZombieCheck_test ** @see sync-classlock.hpp ** @see depend.hpp */ @@ -40,20 +41,38 @@ #include "lib/error.hpp" +#include +#include + namespace lib { namespace error = lumiera::error; + using std::string; + /** * Automatic lifecycle tracker, to produce an alarm when accessing objects after deletion. + * @warning ensure the ZombieCheck instance lives in static memory, otherwise it won't work. */ class ZombieCheck { bool deceased_ = false; + char zombieID_[42]{}; public: + /** + * install a zombie check, tagged with the given id. + * When invoked after death, the raised error::Fatal + * includes this ID in the diagnostic message. + * @remark recommended to use util::typeStr + */ + ZombieCheck (string id) + { + std::strncpy(zombieID_, id.c_str(), 41); + } + ZombieCheck() = default; ~ZombieCheck() { @@ -69,10 +88,20 @@ namespace lib { operator() () const { if (deceased_) - throw error::Fatal("Already deceased object called out of order during Application shutdown. " - "Lumiera Policy violated: Dependencies must not be used from destructors." + throw error::Fatal(buildDiagnosticMessage() ,error::LUMIERA_ERROR_LIFECYCLE); } + + private: + string + buildDiagnosticMessage() const + { + string msg{"Already deceased object called out of order during Application shutdown. " + "Lumiera Policy violated: Dependencies must not be used from destructors."}; + if (zombieID_[0]) + msg += " Offender = "+string{zombieID_}; + return msg; + } }; diff --git a/tests/25fundamental.tests b/tests/25fundamental.tests index f18b6dff9..f42fe79cb 100644 --- a/tests/25fundamental.tests +++ b/tests/25fundamental.tests @@ -257,3 +257,8 @@ return: 0 END +TEST "Zombie tripwire" ZombieCheck_test < + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + +/** @file zombie-check-test.cpp + ** unit test \ref Singleton_test + */ + + +#include "lib/test/run.hpp" +#include "lib/test/test-helper.hpp" +#include "lib/zombie-check.hpp" +#include "lib/util.hpp" + +#include + +using util::contains; +using util::isnil; +using std::string; + + +namespace lib { +namespace test{ + + + + + + + /**********************************************************************//** + * @test verify the ability to trap access to deceased objects. + * @remark For actual usage, the zombie detector needs to be planted into + * static memory. This test can only verify the trigger mechanics. + * @see zombie-check.hpp + * @see lib::DependencyFactory::zombieCheck + */ + class ZombieCheck_test : public Test + { + + virtual void + run (Arg) + { + auto zombieID = randStr(50); + ZombieCheck trap{zombieID}; + CHECK (not trap); + + trap.~ZombieCheck(); // note: unconventional kill + CHECK (trap); // accessing deceased object... + + try { // + trap(); // trigger the tripwire + } + catch(lumiera::error::Fatal& casuality) + { + string obituary = casuality.what(); + CHECK (not isnil (obituary)); + CHECK ( contains (obituary, zombieID.substr(0,41))); + CHECK (not contains (obituary, zombieID)); + } + } + }; + + + + /** Register this test class... */ + LAUNCHER (ZombieCheck_test, "unit common"); + + + +}} // namespace lib::test diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 9940b6772..b37e342cc 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -2944,7 +2944,7 @@ - + @@ -2959,6 +2959,7 @@ + @@ -3017,7 +3018,7 @@ - + @@ -3055,8 +3056,8 @@ - - + + @@ -3079,14 +3080,14 @@ - - + + - + @@ -3098,7 +3099,7 @@ - + @@ -3125,7 +3126,7 @@ - + @@ -3194,7 +3195,7 @@ - + @@ -3264,11 +3265,89 @@ - + - - + + + + + + + + + +

+ 0000001180: INFO: subsystem-runner.hpp:208: worker_3: sigTerm: Subsystem 'Lumiera GTK GUI' terminated. +

+

+ 0000001181: NOTICE: appstate.cpp:170: thread_1: maybeWait: Shutting down Lumiera... +

+

+ 0000001182: ALERT: appstate.cpp:174: thread_1: maybeWait: Triggering emergency exit... +

+

+ 0000001243: WARNING: interfaceregistry.c:199: thread_1: lumiera_interfaceregistry_bulkremove_interfaces: ENTRY NOT FOUND in interfaceregistry at clean-up of interface lumieraorg_Gui, instance lumieraorg_GuiStarterPlugin +

+

+ +

+

+ (lumiera:9719): Gtk-CRITICAL **: gtk_widget_is_drawable: assertion 'GTK_IS_WIDGET (widget)' failed +

+

+ +

+

+ (lumiera:9719): Pango-CRITICAL **: pango_layout_get_cursor_pos: assertion 'index >= 0 && index <= layout->length' failed +

+

+ 0000001293: ERR: error-exception.cpp:185: worker_3: lumiera_unexpectedException: ### Lumiera halted due to an unexpected Error ### +

+

+ +

+

+ ### Lumiera halted due to an unexpected Error ### +

+

+ +

+

+ +

+

+ +++ Caught Exception LUMIERA_ERROR_LIFECYCLE:Lifecycle assumptions violated +

+

+ +

+

+ 0000001298: ERR: error-exception.cpp:196: worker_3: lumiera_unexpectedException: +++ caught error::LumieraError<error::LUMIERA_ERROR_FATAL, error::LumieraError<error::LUMIERA_ERROR_LOGIC, Error> > +

+

+ 0000001298! ERR: error-exception.cpp:196: worker_3: lumiera_unexpectedException: +++ messg: Sorry, Lumiera encountered an internal error. +

+

+ 0000001298! ERR: error-exception.cpp:196: worker_3: lumiera_unexpectedException: +++ descr: LUMIERA_ERROR_LIFECYCLE:Lifecycle assumptions violated (Already deceased object called out of order during Application shutdown. Lumiera Policy violated: Dependencies must not be used from destructors. Offender = ClassLock<gui::interact::LocationQuery, s). +

+

+ 0000001299: ERR: error-exception.cpp:212: worker_3: lumiera_unexpectedException: last registered error was.... +

+

+ 0000001299! ERR: error-exception.cpp:212: worker_3: lumiera_unexpectedException: LUMIERA_ERROR_LIFECYCLE:Lifecycle assumptions violated +

+

+ Abgebrochen +

+ + +
+ + + + +