FailureHandling: improved ZombieCheck
now capturing the Zombie's ID ==> surprise, its ClassLock<gui::interact::LocationQuery>
This commit is contained in:
parent
70c8718258
commit
4e94dfd4d9
6 changed files with 219 additions and 17 deletions
|
|
@ -141,7 +141,7 @@ namespace lib {
|
|||
Deleter deleter_;
|
||||
|
||||
public:
|
||||
ZombieCheck zombieCheck;
|
||||
ZombieCheck zombieCheck{util::typeStr<OBJ>()};
|
||||
|
||||
DependencyFactory() = default;
|
||||
~DependencyFactory()
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 <cstring>
|
||||
#include <string>
|
||||
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -257,3 +257,8 @@ return: 0
|
|||
END
|
||||
|
||||
|
||||
TEST "Zombie tripwire" ZombieCheck_test <<END
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
||||
|
|
|
|||
88
tests/basics/zombie-check-test.cpp
Normal file
88
tests/basics/zombie-check-test.cpp
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
ZombieCheck(Test) - verify a trap for accessing deceased objects
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2018, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
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 <string>
|
||||
|
||||
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
|
||||
|
|
@ -2944,7 +2944,7 @@
|
|||
</node>
|
||||
<node COLOR="#338800" CREATED="1538239665856" ID="ID_518505874" MODIFIED="1538263469675" TEXT="EXPAND">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1538281532767" ID="ID_1335570495" MODIFIED="1538281631433" TEXT="Fehler: muß eigens separate GenNode bauen">
|
||||
<node COLOR="#435e98" CREATED="1538281532767" ID="ID_1335570495" MODIFIED="1538365732115" TEXT="Fehler: muß eigens separate GenNode bauen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
|
|
@ -2959,6 +2959,7 @@
|
|||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1538281608933" ID="ID_584897977" MODIFIED="1538281622963" TEXT="muß bool parsen...">
|
||||
|
|
@ -3017,7 +3018,7 @@
|
|||
<icon BUILTIN="info"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1538317075985" ID="ID_712272839" MODIFIED="1538357310679" TEXT="Problem: lumiera Error-Flag übernimmt nur lokale description">
|
||||
<node COLOR="#338800" CREATED="1538317075985" FOLDED="true" ID="ID_712272839" MODIFIED="1538365661558" TEXT="Problem: lumiera Error-Flag übernimmt nur lokale description">
|
||||
<linktarget COLOR="#c4588d" DESTINATION="ID_712272839" ENDARROW="Default" ENDINCLINATION="577;63;" ID="Arrow_ID_428347507" SOURCE="ID_313278942" STARTARROW="None" STARTINCLINATION="341;0;"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1538317102405" ID="ID_1770156379" MODIFIED="1538317106320" TEXT="und die ist hier leer"/>
|
||||
|
|
@ -3055,8 +3056,8 @@
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1538318187819" ID="ID_870746075" MODIFIED="1538318214241" TEXT="Problem: ExecResult nicht ausgewertet">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1538318187819" FOLDED="true" ID="ID_870746075" MODIFIED="1538365651376" TEXT="Problem: ExecResult nicht ausgewertet">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1538318216016" ID="ID_1444888451" MODIFIED="1538318226226" TEXT="Exception wird nicht ausgeworfen"/>
|
||||
<node CREATED="1538318227150" ID="ID_956176289" MODIFIED="1538318230994" TEXT="Loop läuft weiter"/>
|
||||
<node CREATED="1538318231726" ID="ID_373021764" MODIFIED="1538318237104" TEXT="aber Error-State ist gesetzt">
|
||||
|
|
@ -3079,14 +3080,14 @@
|
|||
<node CREATED="1538319193716" ID="ID_1785359217" MODIFIED="1538319206846" TEXT="...das erklärt, warum wir die Ursache nicht sehen"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1538319456089" ID="ID_342927310" MODIFIED="1538319493900" TEXT="Problem: Handler im ProcDispatcher behandelt nur LumieraException speziell">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node CREATED="1538319456089" FOLDED="true" ID="ID_342927310" MODIFIED="1538365654527" TEXT="Problem: Handler im ProcDispatcher behandelt nur LumieraException speziell">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1538319495420" ID="ID_39746243" MODIFIED="1538319501623" TEXT="das stellt zwar hier kein Problem dar"/>
|
||||
<node CREATED="1538319502331" ID="ID_1092806315" MODIFIED="1538319511413" TEXT="und es ist noch der unspezifische Handler da"/>
|
||||
<node CREATED="1538319512146" ID="ID_672632423" MODIFIED="1538319533231" TEXT="aber: problem.what() geht verloren bei std::exception">
|
||||
<icon BUILTIN="forward"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1538319535006" ID="ID_403817336" MODIFIED="1538319566067" TEXT="Fix: Handler kann genausogut auf std::exception abstellen">
|
||||
<node COLOR="#338800" CREATED="1538319535006" ID="ID_403817336" MODIFIED="1538365635663" TEXT="Fix: Handler kann genausogut auf std::exception abstellen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
|
|
@ -3098,7 +3099,7 @@
|
|||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
@ -3125,7 +3126,7 @@
|
|||
<node CREATED="1538281715646" ID="ID_1541383645" MODIFIED="1538281762796" TEXT="emergency shutdown">
|
||||
<icon BUILTIN="full-3"/>
|
||||
<node CREATED="1538320876787" ID="ID_1528655784" MODIFIED="1538320883630" TEXT="Subsystem-Shutdown">
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1538320884769" ID="ID_707965628" MODIFIED="1538357472940" TEXT="Problem: re-entrance Bug">
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1538320884769" FOLDED="true" ID="ID_707965628" MODIFIED="1538365685651" TEXT="Problem: re-entrance Bug">
|
||||
<icon BUILTIN="hourglass"/>
|
||||
<node CREATED="1538320904127" ID="ID_1958182633" MODIFIED="1538320932319" TEXT="shutdownAll() ruft indirekt/rekursiv sigTerm()">
|
||||
<node COLOR="#435e98" CREATED="1538321043388" ID="ID_1860084270" MODIFIED="1538348459443" TEXT="fragt sich, warum">
|
||||
|
|
@ -3194,7 +3195,7 @@
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1538322674991" ID="ID_371763142" MODIFIED="1538359354152" TEXT="Problem: triggerShutdown nicht wasserdicht">
|
||||
<node CREATED="1538322674991" FOLDED="true" ID="ID_371763142" MODIFIED="1538365689019" TEXT="Problem: triggerShutdown nicht wasserdicht">
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
<node CREATED="1538322708227" ID="ID_1994833744" MODIFIED="1538322772297" TEXT="kann sterben">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
|
|
@ -3264,11 +3265,89 @@
|
|||
</html>
|
||||
</richcontent>
|
||||
<icon BUILTIN="full-5"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1538281782245" ID="ID_888818129" MODIFIED="1538281805087" TEXT="welcher...?">
|
||||
<node COLOR="#435e98" CREATED="1538281782245" ID="ID_888818129" MODIFIED="1538365399555" TEXT="welcher...">
|
||||
<icon BUILTIN="help"/>
|
||||
<node CREATED="1538326229581" ID="ID_687910017" MODIFIED="1538326243254" TEXT="mit dem Debugger nicht zu fassen...."/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1538326244075" ID="ID_362650638" MODIFIED="1538326258434" TEXT="Aufgabe: Zobmie-ID statisch speichern">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1538326244075" ID="ID_362650638" MODIFIED="1538365389966" TEXT="Aufgabe: Zobmie-ID statisch speichern">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1538365422252" ID="ID_1782663880" MODIFIED="1538365532058" TEXT="Offender = ClassLock<gui::interact::LocationQuery>">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
0000001180: INFO: subsystem-runner.hpp:208: worker_3: sigTerm: Subsystem 'Lumiera GTK GUI' terminated.
|
||||
</p>
|
||||
<p>
|
||||
0000001181: NOTICE: appstate.cpp:170: thread_1: maybeWait: Shutting down Lumiera...
|
||||
</p>
|
||||
<p>
|
||||
0000001182: ALERT: appstate.cpp:174: thread_1: maybeWait: Triggering emergency exit...
|
||||
</p>
|
||||
<p>
|
||||
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
|
||||
</p>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
(lumiera:9719): Gtk-CRITICAL **: gtk_widget_is_drawable: assertion 'GTK_IS_WIDGET (widget)' failed
|
||||
</p>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
(lumiera:9719): Pango-CRITICAL **: pango_layout_get_cursor_pos: assertion 'index >= 0 && index <= layout->length' failed
|
||||
</p>
|
||||
<p>
|
||||
0000001293: ERR: error-exception.cpp:185: worker_3: lumiera_unexpectedException: ### Lumiera halted due to an unexpected Error ###
|
||||
</p>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
### Lumiera halted due to an unexpected Error ###
|
||||
</p>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
+++ Caught Exception LUMIERA_ERROR_LIFECYCLE:Lifecycle assumptions violated
|
||||
</p>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
0000001298: ERR: error-exception.cpp:196: worker_3: lumiera_unexpectedException: +++ caught error::LumieraError<error::LUMIERA_ERROR_FATAL, error::LumieraError<error::LUMIERA_ERROR_LOGIC, Error> >
|
||||
</p>
|
||||
<p>
|
||||
0000001298! ERR: error-exception.cpp:196: worker_3: lumiera_unexpectedException: +++ messg: Sorry, Lumiera encountered an internal error.
|
||||
</p>
|
||||
<p>
|
||||
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).
|
||||
</p>
|
||||
<p>
|
||||
0000001299: ERR: error-exception.cpp:212: worker_3: lumiera_unexpectedException: last registered error was....
|
||||
</p>
|
||||
<p>
|
||||
0000001299! ERR: error-exception.cpp:212: worker_3: lumiera_unexpectedException: LUMIERA_ERROR_LIFECYCLE:Lifecycle assumptions violated
|
||||
</p>
|
||||
<p>
|
||||
Abgebrochen
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1538365543884" ID="ID_534885692" MODIFIED="1538365573259" TEXT="man beachte auch die zwei GTK-Assertions nach dem GUI-Shutdown">
|
||||
<icon BUILTIN="forward"/>
|
||||
</node>
|
||||
<node CREATED="1538365584159" ID="ID_998255150" MODIFIED="1538365599464" TEXT="wieso läuft da noch GUI-code??"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1538281788117" ID="ID_1747014683" MODIFIED="1538281816152" TEXT="wie konnte das passieren....">
|
||||
|
|
|
|||
Loading…
Reference in a new issue