summaryrefslogtreecommitdiff
path: root/indra/llcommon/llsingleton.cpp
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2019-08-20 12:36:06 -0400
committerNat Goodspeed <nat@lindenlab.com>2019-08-20 12:36:06 -0400
commit54b98cb8c1302a1da5779d8968e54e5be641e644 (patch)
tree4fb8ebf2dcd72671e7e3c84b3ccd4e970bb360c4 /indra/llcommon/llsingleton.cpp
parent310db14beefc29ee72e0d13f0cb63cb2958ebf68 (diff)
DRTVWR-493: Defend LL[Param]Singleton against ctor/init exceptions.
An exception in the LLSingleton subclass constructor, or in its initSingleton() method, could leave the LLSingleton machinery in a bad state: the failing instance would remain in the MasterList, also on the stack of initializing LLSingletons. Catch exceptions in either and perform relevant cleanup. This problem is highlighted by test programs, in which LL_ERRS throws an exception rather than crashing the whole process. In the relevant catch clauses, clean up the initializing stack BEFORE logging. Otherwise we get tangled up recording bogus dependencies. Move capture_dependency() out of finishInitializing(): it must be called by every valid getInstance() call, both from LLSingleton and LLParamSingleton. Introduce new CONSTRUCTED EInitState value to distinguish "have called the constructor but not yet the initSingleton() method" from "currently within initSingleton() method." This is transient, but we execute the 'switch' on state within that moment. One could argue that the previous enum used INITIALIZING for current CONSTRUCTED, and INITIALIZED meant INITIALIZING too, but this is clearer. Introduce template LLSingletonBase::classname() helper methods to clarify verbose demangle(typeid(stuff).name()) calls. Similarly, introduce LLSingleton::pop_initializing() shorthand method.
Diffstat (limited to 'indra/llcommon/llsingleton.cpp')
-rw-r--r--indra/llcommon/llsingleton.cpp40
1 files changed, 25 insertions, 15 deletions
diff --git a/indra/llcommon/llsingleton.cpp b/indra/llcommon/llsingleton.cpp
index adf72bf700..88527a3d31 100644
--- a/indra/llcommon/llsingleton.cpp
+++ b/indra/llcommon/llsingleton.cpp
@@ -150,7 +150,7 @@ void LLSingletonBase::pop_initializing()
if (list.empty())
{
logerrs("Underflow in stack of currently-initializing LLSingletons at ",
- demangle(typeid(*this).name()).c_str(), "::getInstance()");
+ classname(this).c_str(), "::getInstance()");
}
// Now we know list.back() exists: capture it
@@ -172,8 +172,8 @@ void LLSingletonBase::pop_initializing()
if (back != this)
{
logerrs("Push/pop mismatch in stack of currently-initializing LLSingletons: ",
- demangle(typeid(*this).name()).c_str(), "::getInstance() trying to pop ",
- demangle(typeid(*back).name()).c_str());
+ classname(this).c_str(), "::getInstance() trying to pop ",
+ classname(back).c_str());
}
// log AFTER popping so logging singletons don't cry circularity
@@ -216,7 +216,7 @@ void LLSingletonBase::log_initializing(const char* verb, const char* name)
ri != rend; ++ri)
{
LLSingletonBase* sb(*ri);
- LL_CONT << ' ' << demangle(typeid(*sb).name());
+ LL_CONT << ' ' << classname(sb);
}
LL_ENDL;
}
@@ -250,7 +250,7 @@ void LLSingletonBase::capture_dependency(list_t& initializing, EInitState initSt
// 'found' is an iterator; *found is an LLSingletonBase*; **found
// is the actual LLSingletonBase instance.
LLSingletonBase* foundp(*found);
- out << demangle(typeid(*foundp).name()) << " -> ";
+ out << classname(foundp) << " -> ";
}
// We promise to capture dependencies from both the constructor
// and the initSingleton() method, so an LLSingleton's instance
@@ -264,7 +264,7 @@ void LLSingletonBase::capture_dependency(list_t& initializing, EInitState initSt
if (initState == CONSTRUCTING)
{
logerrs("LLSingleton circularity in Constructor: ", out.str().c_str(),
- demangle(typeid(*this).name()).c_str(), "");
+ classname(this).c_str(), "");
}
else if (it_next == initializing.end())
{
@@ -275,14 +275,14 @@ void LLSingletonBase::capture_dependency(list_t& initializing, EInitState initSt
// Example: LLNotifications singleton initializes default channels.
// Channels register themselves with singleton once done.
logdebugs("LLSingleton circularity: ", out.str().c_str(),
- demangle(typeid(*this).name()).c_str(), "");
+ classname(this).c_str(), "");
}
else
{
// Actual circularity with other singleton (or single singleton is used extensively).
// Dependency can be unclear.
logwarns("LLSingleton circularity: ", out.str().c_str(),
- demangle(typeid(*this).name()).c_str(), "");
+ classname(this).c_str(), "");
}
}
else
@@ -295,8 +295,8 @@ void LLSingletonBase::capture_dependency(list_t& initializing, EInitState initSt
if (current->mDepends.insert(this).second)
{
// only log the FIRST time we hit this dependency!
- logdebugs(demangle(typeid(*current).name()).c_str(),
- " depends on ", demangle(typeid(*this).name()).c_str());
+ logdebugs(classname(current).c_str(),
+ " depends on ", classname(this).c_str());
}
}
}
@@ -355,19 +355,19 @@ void LLSingletonBase::cleanupAll()
sp->mCleaned = true;
logdebugs("calling ",
- demangle(typeid(*sp).name()).c_str(), "::cleanupSingleton()");
+ classname(sp).c_str(), "::cleanupSingleton()");
try
{
sp->cleanupSingleton();
}
catch (const std::exception& e)
{
- logwarns("Exception in ", demangle(typeid(*sp).name()).c_str(),
+ logwarns("Exception in ", classname(sp).c_str(),
"::cleanupSingleton(): ", e.what());
}
catch (...)
{
- logwarns("Unknown exception in ", demangle(typeid(*sp).name()).c_str(),
+ logwarns("Unknown exception in ", classname(sp).c_str(),
"::cleanupSingleton()");
}
}
@@ -382,7 +382,7 @@ void LLSingletonBase::deleteAll()
{
// Capture the class name first: in case of exception, don't count on
// being able to extract it later.
- const std::string name = demangle(typeid(*sp).name());
+ const std::string name = classname(sp);
try
{
// Call static method through instance function pointer.
@@ -459,7 +459,17 @@ void LLSingletonBase::logerrs(const char* p1, const char* p2, const char* p3, co
log(LLError::LEVEL_ERROR, p1, p2, p3, p4);
// The other important side effect of LL_ERRS() is
// https://www.youtube.com/watch?v=OMG7paGJqhQ (emphasis on OMG)
- LLError::crashAndLoop(std::string());
+ std::ostringstream out;
+ out << p1 << p2 << p3 << p4;
+ auto crash{ LLError::getFatalFunction() };
+ if (crash)
+ {
+ crash(out.str());
+ }
+ else
+ {
+ LLError::crashAndLoop(out.str());
+ }
}
std::string LLSingletonBase::demangle(const char* mangled)