Good day,

I believe there's a problem with the use of static local variables 
w/non-trivial constructors within log4cxx code (bug LOG4CXX-159, 
http://issues.apache.org/jira/browse/LOGCXX-159 ). Log4cxx contains things like 
this (from ndc.cpp):

const LogString& NDC::getNull() {
    static LogString nullStr(LOG4CXX_STR("null"));
    return nullStr;
}

I think there are two major problems with this (and similar) code:

1) I think it is not thread safe. Local statics are initialized the first time 
the enclosing function is called (C++'98 ISO standard, section 6.7). If two 
threads call it at about the same time from different threads, they may both 
try to initialize the static local at once, effectively executing the object's 
constructor on the same object simultaneously. [I vaguely remember reading 
something about Visual C++ generating code that ensures this doesn't happen, 
using mutexes or something... even if it's true, other compilers most likely 
wouldn't do that].

2) The order of construction and (especially) destruction of such local statics 
is ... "interesting", esp. w.r.t. static objects defined in other object files. 
LOG4CXX-159 contains a couple of example programs that demonstrate this, but 
the bottom line is, such local static variables are sometimes destructed before 
static objects in user code are, which in my case caused SEGFAULTs.

I understand static locals were introduced in favor of globals to make sure 
they are initialized as necessary... however there are still instances where 
global statics are used (Level::ALL, etc); are there any plans to do anything 
about them?

Also, as suggested by Curt in that JIRA discussion, arranging a call to 
something like "Logger::getLogger(...)->forcedLog(...)" before anything else 
happens in user code (i.e., from some static ctor), seems to exercise most of 
the static local initialization, but this doesn't always work (I can give 
specific examples). Plus one needs to configure() log4cxx before doing that.

Anyway, a possible solution that ensures *all* log4cxx statics are initialized 
before anything the user code might possibly do could be this: convert all 
statics (both local and global) to [static] global pointers and 
initialize/uninitialize (new/delete) them explicitely in an additional global 
init/uninit function. Then, add a call to init() at the global level inside one 
of log4cxx headers that is always #include'd in the user code (config.h?); that 
way init() will be called before any user constructors.

Unfortunately this will probably require some changes to the public API -- 
since we can't use true statics, public static class member variables would 
have to be changed to functions that return references.

Thoughts, comments?
D.


Reply via email to