a better solution to reject out-of-order static access after shutdown
Static initialisation and shutdown can be intricate; but in fact they work quite precise and deterministic, once you understand the rules of the game. In the actual case at hand the ClassLock was already destroyed, and it must be destroyed at that point, according to the standard. Simply because it is created on-demand, *after* the initialisation of the static DependencyFactory, which uses this lock, and so its destructor must be called befor the dtor of DependencyFactory -- which is precisely what happens. So there is no need to establish a special secure "base runtime system", and this whole idea is ill-guided. I'll thus close ticket #1133 as wontfix Conflicts: src/lib/dependable-base.hpp
This commit is contained in:
parent
a8273283d1
commit
21fdce0dfc
4 changed files with 215 additions and 28 deletions
|
|
@ -46,7 +46,7 @@ of the service interface.
|
|||
Dependency::
|
||||
A relation at implementation level and thus a local property of an individual component. A dependency
|
||||
is something we need in order to complete the task at hand, yet a dependency lies beyond that task and
|
||||
relates to concerns outside the scope and theme of this actual task. Wich means, a dependency is not
|
||||
relates to concerns outside the scope and theme of this actual task. Which means, a dependency is not
|
||||
introduced by the task or part of the task, rather the task is the reason why some entity dealing with
|
||||
it needs to _pull_ the dependency, in order to be able to handle the task. So essentially, dependencies
|
||||
are accessed on-demand. Dependencies might be other components or services, and typically the user
|
||||
|
|
@ -146,6 +146,28 @@ Any valuable work done by the user should be accepted and recorded persistently
|
|||
session are logged, like in a database. The user may still save snapshots, but basically any actual change
|
||||
is immediately recorded persistently. And thus we may crash without remorse.
|
||||
|
||||
Static initialisation and shutdown
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
A lot of fine points can be made about when precisely static objects in C\++ will be initialised or destroyed.
|
||||
However, anything beyond the scope of `main()` is not meant to be used for regular application code. Extended
|
||||
initialisation, dependency management and decommissioning -- when actually necessary -- should be part of the
|
||||
application code proper.footnote:[this is established ``best practice'' for good reasons. The interplay of
|
||||
static lifespan, various translation units and even dynamically loaded libraries together with shared access
|
||||
becomes intricate and insidious quite easily. And since in theory any static function could use some static
|
||||
variable residing in another translation unit, it is always possible to construct a situation where objects
|
||||
are accessed after being destroyed. Typically such objects do not even look especially ``dead'', since the
|
||||
static storage remains in place and still holds possibly sane values. Static (global) variables, like raw
|
||||
pointers, allow to subvert the deterministic automatic memory management, which otherwise is one of the
|
||||
greatest strengths of C++. Whenever we find ourselves developing extended collaborative logic based on
|
||||
several statics, we should consider to transform this logic into regular objects, which are easier to
|
||||
test and better to reason about. If it really can not be avoided to use such units of logic from a
|
||||
static context, it should at least be packaged as a single object, plus we should ensure this logic
|
||||
can only be accessed through a regular (non static) object as front-end. Packaged this way, the
|
||||
most common and dangerous pitfalls with statics can be avoided.] And since Lumiera indeed allows
|
||||
for link:{ldoc}/technical/library/Dependencies.html[[lazily initialised dependencies], we
|
||||
establish the policy that *destructors must not rely on dependencies*. In fact, they should
|
||||
not do any tangible work at all, beyond releasing other resources.
|
||||
|
||||
Lifecycle Events
|
||||
~~~~~~~~~~~~~~~~
|
||||
The Application as a whole conducts a well defined lifecycle; whenever transitioning to the next phase,
|
||||
|
|
|
|||
|
|
@ -125,14 +125,25 @@ namespace lib {
|
|||
Creator creator_;
|
||||
Deleter deleter_;
|
||||
|
||||
bool deceased_ =false;
|
||||
public:
|
||||
DependencyFactory() = default;
|
||||
~DependencyFactory()
|
||||
{
|
||||
deceased_ = true;
|
||||
if (deleter_)
|
||||
deleter_();
|
||||
}
|
||||
|
||||
void
|
||||
zombieCheck()
|
||||
{
|
||||
if (deceased_)
|
||||
throw error::Fatal("DependencyFactory invoked out of order during Application shutdown. "
|
||||
"Lumiera Policy violated: Dependencies must not be used from destructors."
|
||||
,error::LUMIERA_ERROR_LIFECYCLE);
|
||||
}
|
||||
|
||||
OBJ*
|
||||
operator() ()
|
||||
{
|
||||
|
|
@ -295,6 +306,7 @@ namespace lib {
|
|||
SRV* object = instance.load (std::memory_order_acquire);
|
||||
if (!object)
|
||||
{
|
||||
factory.zombieCheck();
|
||||
Lock guard;
|
||||
|
||||
object = instance.load (std::memory_order_relaxed);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
DEPENDABLE-BASE.hpp - fundamental structures with extended lifespan
|
||||
ZOMBIE-CHECK.hpp - flatliner self-detection
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2018, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
|
@ -21,15 +21,16 @@
|
|||
*/
|
||||
|
||||
/** @file dependable-base.hpp
|
||||
** Static container to hold basic entities needed during static init and shutdown.
|
||||
** Detector to set off alarm when (re)using deceased objects.
|
||||
** @see sync-classlock.hpp
|
||||
** @see depend.hpp
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LIB_DEPENDABLE_BASE_H
|
||||
#define LIB_DEPENDABLE_BASE_H
|
||||
#ifndef LIB_ZOMBIE_CHECK_H
|
||||
#define LIB_ZOMBIE_CHECK_H
|
||||
|
||||
#include "lib/del-stash.hpp"
|
||||
#include "lib/nocopy.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
|
@ -54,8 +55,8 @@ namespace lib {
|
|||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////TICKET #1133 damn it. How the hell do we determine when the object is initialised...?
|
||||
///////////////////////////////////////////////////////////////TICKET #1133 ........ Looks like the whole approach is ill guided
|
||||
template<class X>
|
||||
uint Holder<X>::accessed_;
|
||||
|
||||
} // (End) nifty implementation details
|
||||
|
||||
|
|
@ -94,4 +95,4 @@ namespace lib {
|
|||
|
||||
|
||||
} // namespace lib
|
||||
#endif /*LIB_DEPENDABLE_BASE_H*/
|
||||
#endif /*LIB_ZOMBIE_CHECK_H*/
|
||||
|
|
@ -28294,9 +28294,15 @@
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1522454132616" ID="ID_1054219137" MODIFIED="1522456961034" TEXT="brauchen wir einen Basis-Layer?">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node CREATED="1522455499003" ID="ID_323278727" MODIFIED="1522455503078" TEXT="vermutlich ja"/>
|
||||
<node COLOR="#990000" CREATED="1522454132616" ID="ID_1054219137" MODIFIED="1522547155318" TEXT="brauchen wir einen Basis-Layer?">
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
<node CREATED="1522455499003" ID="ID_323278727" MODIFIED="1522547122649" TEXT="vermutlich ja">
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1522547104318" ID="ID_1075985632" MODIFIED="1522547119436" TEXT="nein besser nicht">
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
<node CREATED="1522455507937" ID="ID_1029197196" MODIFIED="1522457177939" TEXT="für wen?">
|
||||
<linktarget COLOR="#512c6f" DESTINATION="ID_1029197196" ENDARROW="Default" ENDINCLINATION="-299;0;" ID="Arrow_ID_845867084" SOURCE="ID_22169859" STARTARROW="None" STARTINCLINATION="1419;0;"/>
|
||||
<node CREATED="1522455514361" ID="ID_1288380071" MODIFIED="1522455518148" TEXT="ClassLock"/>
|
||||
|
|
@ -28444,11 +28450,14 @@
|
|||
</node>
|
||||
<node CREATED="1515975600368" ID="ID_896967532" MODIFIED="1515976656307" TEXT="für Unit-Tests">
|
||||
<linktarget COLOR="#c1a9ac" DESTINATION="ID_896967532" ENDARROW="Default" ENDINCLINATION="46;-116;" ID="Arrow_ID_618937075" SOURCE="ID_1385819621" STARTARROW="None" STARTINCLINATION="-41;116;"/>
|
||||
<node COLOR="#338800" CREATED="1522506758042" ID="ID_1422898694" MODIFIED="1522506783584" TEXT="DependInject<I>::Local<MOC>">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1522457000411" ID="ID_736034555" MODIFIED="1522457004364" TEXT="Basis-System">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1522457000411" ID="ID_736034555" MODIFIED="1522547807040" TEXT="Basis-System">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1522457035478" ID="ID_1692167558" MODIFIED="1522457039855" TEXT="#1133 dependable base system">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
|
|
@ -28457,29 +28466,172 @@
|
|||
</node>
|
||||
<node CREATED="1522506451269" ID="ID_55500881" MODIFIED="1522506467912" TEXT="Anforderungen">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1522506486504" ID="ID_1878547223" MODIFIED="1522506497312" TEXT="Scope jeweils für einen Target-Typ">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node CREATED="1522506486504" ID="ID_1878547223" MODIFIED="1522547691142" TEXT="Scope jeweils für einen Payload-Typ"/>
|
||||
<node CREATED="1522506518348" ID="ID_1014457759" MODIFIED="1522547692821" TEXT="gemeinsame statische Storage für diesen Typ"/>
|
||||
<node CREATED="1522506636907" ID="ID_662985730" MODIFIED="1522547695756" TEXT="ctor/dtor für Payload werden aufgerufen">
|
||||
<node CREATED="1522511826327" ID="ID_200801018" MODIFIED="1522511828746" TEXT="ctor">
|
||||
<node CREATED="1522518918379" ID="ID_261980616" MODIFIED="1522518931653" TEXT="bevor Payload benötigt wird"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1522506518348" ID="ID_1014457759" MODIFIED="1522506526379" TEXT="gemeinsame statische Storage für diesen Typ">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node CREATED="1522511829358" ID="ID_509925407" MODIFIED="1522511830546" TEXT="dtor">
|
||||
<node CREATED="1522518935777" ID="ID_1823418824" MODIFIED="1522518941700" TEXT=""möglichst spät""/>
|
||||
<node CREATED="1522518942263" ID="ID_203967064" MODIFIED="1522518945211" TEXT="aber zuverlässig"/>
|
||||
</node>
|
||||
<node CREATED="1522514043309" ID="ID_1380359037" MODIFIED="1522514045656" TEXT="wann?">
|
||||
<node CREATED="1522514050796" ID="ID_191668372" MODIFIED="1522514056079" TEXT="pro Typ">
|
||||
<node CREATED="1522518875353" ID="ID_1629001557" MODIFIED="1522518882228" TEXT="ist das überhaupt möglich?"/>
|
||||
<node CREATED="1522518882744" ID="ID_1818509600" MODIFIED="1522518901851" TEXT="läuft wieder auf ein Template-generiertes Static hinaus">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1522457084472" ID="ID_1662610871" MODIFIED="1522457093048" TEXT="Schwartz-Counter implementieren">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1522457095319" ID="ID_1811034910" MODIFIED="1522457208551" TEXT="generisch">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node CREATED="1522514056835" ID="ID_1693314028" MODIFIED="1522514067974" TEXT="für alle DependableBase">
|
||||
<node CREATED="1522514071649" ID="ID_433197904" MODIFIED="1522514079988" TEXT="erfordert DelStash"/>
|
||||
<node CREATED="1522514086711" ID="ID_1216342984" MODIFIED="1522514117422" TEXT="an einem sicheren Ort"/>
|
||||
<node CREATED="1522514120075" ID="ID_664406309" MODIFIED="1522514130012" TEXT="Idee: shared_ptr hierfür">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1522457099278" ID="ID_293179749" MODIFIED="1522457209831" TEXT="wasserdicht mit Header-Lösung">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node CREATED="1522514148983" ID="ID_1331551985" MODIFIED="1522514165872" TEXT="jede neue DependableBase registriert sich"/>
|
||||
<node CREATED="1522514307456" ID="ID_930138927" MODIFIED="1522514332529" TEXT="Problem: Deregistrierung von Einträgen aus shared libs">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node CREATED="1522541153861" ID="ID_1598087575" MODIFIED="1522541200548" TEXT="Problem: muß auch jeden einzelnen ctor tracken">
|
||||
<icon BUILTIN="stop-sign"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1522457113044" ID="ID_1913798256" MODIFIED="1522457130605" TEXT="umzustellen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1522457119491" ID="ID_715588139" MODIFIED="1522457204997" TEXT="ClassLock">
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1522506685708" ID="ID_172729748" MODIFIED="1522547698341" TEXT="...allerdings über einen Refcount für den Scope"/>
|
||||
<node CREATED="1522506808180" ID="ID_962156028" MODIFIED="1522547700284" TEXT="Refcount verwendet Atomics"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1522518973331" ID="ID_136789565" MODIFIED="1522518988634" TEXT="Design-Dilemma">
|
||||
<icon BUILTIN="broken-line"/>
|
||||
<node CREATED="1522519009127" ID="ID_989945730" MODIFIED="1522519024864" TEXT="einfache Statics "sollten" lokal funktionieren"/>
|
||||
<node CREATED="1522519025972" ID="ID_714585131" MODIFIED="1522519142036" TEXT="das Problem ist, wenn man sich auf externe Statics abstützt">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
...und das kann ziemlich indirekt passieren.
|
||||
</p>
|
||||
<p>
|
||||
Beispiel ist das ClassLock. Das ist ein Front-End, und verwendet verdeckt wieder einen Static.
|
||||
</p>
|
||||
<p>
|
||||
Und genau <i>dafür</i> gibt es anscheinend keine Garantieren
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<node CREATED="1522541262254" ID="ID_1609622536" MODIFIED="1522541279648" TEXT="genauer: wenn man sich auf on-demand (local) statics abstützt"/>
|
||||
<node CREATED="1522541280331" ID="ID_296029834" MODIFIED="1522541319853">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
C++ hällt die Erzeugungs/Zerstörungs-Reihenfolge <b>exakt</b> ein
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1522541321043" ID="ID_966332775" MODIFIED="1522541356223">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
d.h. wenn das local static <i>später erzeugt</i> wird, wird es <b>vor</b>  dem Hauptobjekt zerstört
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1522519161785" ID="ID_608910503" MODIFIED="1522519198800" TEXT="aus Gründen der Code-Organisation will man aber nicht immer alles in ein Objekt packen"/>
|
||||
<node CREATED="1522519253645" ID="ID_1316230973" MODIFIED="1522519267958" TEXT="aber eine wirklich wasserdichte, genersche Lösung ist komplex bis unmöglich"/>
|
||||
<node CREATED="1522519269002" ID="ID_1313794115" MODIFIED="1522519283292" TEXT="und statt einer halb-wasserdichten Lösung könnte man ja einfache Statics verwenden"/>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1522519308709" ID="ID_1997666438" MODIFIED="1522547255792" TEXT="Beschluß">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1522547261520" ID="ID_539336828" MODIFIED="1522547285145" TEXT="das ist insgesamt eine schlechte Idee">
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
</node>
|
||||
<node CREATED="1522547285877" ID="ID_1921668956" MODIFIED="1522547323528">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Statische Initialisierung funktioniert <b>präzise</b>, korrekt und <b>zuverlässig</b>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node CREATED="1522547330726" ID="ID_994306275" MODIFIED="1522547749968" TEXT="C++ stellt das eigens sicher -- man muß es nur erst mal verstehen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Der Aufruf von Konstrukturen statischer Objekte konstituiert eine (dynamische) Reihenfolge.
|
||||
</p>
|
||||
<p>
|
||||
Desktuktoren werden exakt rückwärts in dieser Reihenfolge aufgerufen.
|
||||
</p>
|
||||
<p>
|
||||
Statische Objektfelder werden vor der ersten Verwendung der Klassen<b>definition</b>  initialisiert
|
||||
</p>
|
||||
<p>
|
||||
Dagegen Funktions-lokale statische Variablen werden initialisiert, wenn der Kontrollfluß sie zum ersten mal berührt.
|
||||
</p>
|
||||
<p>
|
||||
Wenn ein Konstruktor ein statisches Feld verwendet, dann wird dieses Feld vor dem Konstruktor erzeugt.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
Beachte: in jedem dieser Fälle wird auch die o.g. Reihenfolge konstituiert.
|
||||
</p>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
<p>
|
||||
<u>Corollar</u>: wenn man ein Meyer's Singleton erst indirekt aus dem Implementierungs-Code verwendet,
|
||||
</p>
|
||||
<p>
|
||||
so wird es garantiert zerstört, <i>bevor</i> der Destruktor des aufrufenden Objekts läuft.
|
||||
</p>
|
||||
<p>
|
||||
Hallo ClassLock...
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<icon BUILTIN="info"/>
|
||||
</node>
|
||||
<node CREATED="1522547752788" ID="ID_1333812920" MODIFIED="1522547762343" TEXT="eine handgeschriebene Lösung kann da nicht besser sein"/>
|
||||
<node CREATED="1522547763547" ID="ID_1065493509" MODIFIED="1522547771413" TEXT="und verschiebt nur das Problem nach hinten"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1522457113044" ID="ID_1913798256" MODIFIED="1522547725898" TEXT="umzustellen">
|
||||
<icon BUILTIN="stop-sign"/>
|
||||
<node CREATED="1522457119491" ID="ID_715588139" MODIFIED="1522547714913" TEXT="ClassLock">
|
||||
<linktarget COLOR="#735d7e" DESTINATION="ID_715588139" ENDARROW="Default" ENDINCLINATION="1087;0;" ID="Arrow_ID_1384015103" SOURCE="ID_1951071885" STARTARROW="None" STARTINCLINATION="-84;86;"/>
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
</node>
|
||||
<node CREATED="1522457132025" ID="ID_828796576" MODIFIED="1522457136460" TEXT="Applikation-Objekt?"/>
|
||||
<node CREATED="1522457132025" ID="ID_828796576" MODIFIED="1522547718346" TEXT="Applikation-Objekt?">
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1522547772617" ID="ID_671236738" MODIFIED="1522547788328" TEXT="besser nur einen Zombie-Check bereitstellen">
|
||||
<icon BUILTIN="flag-pink"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1482524535575" ID="ID_387248900" MODIFIED="1518487921096" TEXT="Extension-System"/>
|
||||
|
|
|
|||
Loading…
Reference in a new issue