log4cxx 在 ~Logger 上引发异常

发布于 2024-11-24 16:41:05 字数 1732 浏览 0 评论 0原文

我刚刚开始使用 log4cxx,通过制作一个小应用程序来熟悉它。 我用 Visual Studio 2005 编译,没有警告或错误。 基本上看起来像:

#includes<...>
...
...
LoggerPtr logger(Logger::getLogger("MyApp"));

void main(...)
{
    //some logs here
}

它按预期工作,直到我在尝试销毁全局 Logger 对象时遇到异常时关闭应用程序。 这是痕迹:

log4cxx.dll!apr_pool_cleanup_kill(apr_pool_t * p=0xdddddddd, const void * data=0x01cf6158, int (void *)* cleanup_fn=0x10174250)  Line 1981 + 0x3 bytes
log4cxx.dll!apr_pool_cleanup_run(apr_pool_t * p=0xdddddddd, void * data=0x01cf6158, int (void *)* cleanup_fn=0x10174250)  Line 2025
log4cxx.dll!apr_thread_mutex_destroy(apr_thread_mutex_t * mutex=0x01cf6158)  Line 133 
log4cxx.dll!log4cxx::helpers::Mutex::~Mutex()  Line 57
log4cxx.dll!log4cxx::Logger::~Logger()  Line 55 + 0xb bytes
log4cxx.dll!log4cxx::Logger::`vbase destructor'()  + 0x19 bytes
log4cxx.dll!log4cxx::Logger::`vector deleting destructor'()  + 0x5a bytes
log4cxx.dll!log4cxx::helpers::ObjectImpl::releaseRef()  Line 46 + 0x39 bytes
log4cxx.dll!log4cxx::Logger::releaseRef()  Line 63
log4cxx.dll!log4cxx::helpers::ObjectPtrT<log4cxx::Logger>::~ObjectPtrT<log4cxx::Logger>()  Line 100 + 0x33 bytes
NodeBHeartBeat.exe!`dynamic atexit destructor for 'logger''()  + 0x2b bytes
msvcr80d.dll!doexit(int code=0x00000000, int quick=0x00000000, int retcaller=0x00000001)  Line 553
msvcr80d.dll!_cexit()  Line 413 + 0xb bytes
msvcr80d.dll!__CRTDLL_INIT(void * hDllHandle=0x6c710000, unsigned long dwReason=0x00000000, void * lpreserved=0x00000001)  Line 389
msvcr80d.dll!_CRTDLL_INIT(void * hDllHandle=0x6c710000, unsigned long dwReason=0x00000000, void * lpreserved=0x00000001)  Line 214 + 0x11 bytes
ntdll.dll!774b9960()

有人知道为什么会发生这种情况吗? 谢谢

I just started with log4cxx by doing a small app to get familiar with it.
I compiled with Visual Studio 2005, no warnings or errors.
Basically looks like :

#includes<...>
...
...
LoggerPtr logger(Logger::getLogger("MyApp"));

void main(...)
{
    //some logs here
}

It works as expected until I close the app when I get an exception while trying to destroy the global Logger object.
Here is the trace:

log4cxx.dll!apr_pool_cleanup_kill(apr_pool_t * p=0xdddddddd, const void * data=0x01cf6158, int (void *)* cleanup_fn=0x10174250)  Line 1981 + 0x3 bytes
log4cxx.dll!apr_pool_cleanup_run(apr_pool_t * p=0xdddddddd, void * data=0x01cf6158, int (void *)* cleanup_fn=0x10174250)  Line 2025
log4cxx.dll!apr_thread_mutex_destroy(apr_thread_mutex_t * mutex=0x01cf6158)  Line 133 
log4cxx.dll!log4cxx::helpers::Mutex::~Mutex()  Line 57
log4cxx.dll!log4cxx::Logger::~Logger()  Line 55 + 0xb bytes
log4cxx.dll!log4cxx::Logger::`vbase destructor'()  + 0x19 bytes
log4cxx.dll!log4cxx::Logger::`vector deleting destructor'()  + 0x5a bytes
log4cxx.dll!log4cxx::helpers::ObjectImpl::releaseRef()  Line 46 + 0x39 bytes
log4cxx.dll!log4cxx::Logger::releaseRef()  Line 63
log4cxx.dll!log4cxx::helpers::ObjectPtrT<log4cxx::Logger>::~ObjectPtrT<log4cxx::Logger>()  Line 100 + 0x33 bytes
NodeBHeartBeat.exe!`dynamic atexit destructor for 'logger''()  + 0x2b bytes
msvcr80d.dll!doexit(int code=0x00000000, int quick=0x00000000, int retcaller=0x00000001)  Line 553
msvcr80d.dll!_cexit()  Line 413 + 0xb bytes
msvcr80d.dll!__CRTDLL_INIT(void * hDllHandle=0x6c710000, unsigned long dwReason=0x00000000, void * lpreserved=0x00000001)  Line 389
msvcr80d.dll!_CRTDLL_INIT(void * hDllHandle=0x6c710000, unsigned long dwReason=0x00000000, void * lpreserved=0x00000001)  Line 214 + 0x11 bytes
ntdll.dll!774b9960()

Anybody has any idea why is this happening ?
Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

夏了南城 2024-12-01 16:41:05

我通过简单地将“0”分配给记录器指针来解决这个问题。

这个魔术位于 log4cxx 源代码内的文件 src/main/include/log4cxx/helpers/objectptr.h 中

,即,releaseRef() 间接控制对象销毁顺序。

    ...
    ...
        ObjectPtrT& operator=(const int& null) //throw(IllegalArgumentException)
             {
                    //
                    //   throws IllegalArgumentException if null != 0
                    //
                    ObjectPtrBase::checkNull(null);
                    T* oldPtr = exchange(0);
                    if (oldPtr != 0) {
                       oldPtr->releaseRef();
                    }
                    return *this;
             }
...
...

因此,对于您的代码,只需在末尾添加一行:

#includes<...>
...
...
LoggerPtr logger(Logger::getLogger("MyApp"));

void main(...)
{
    //some logs here

    logger = 0; // RELEASE REFERENCE TO POINTER

   // Make sure no other reference to logger exist
   // ie: a thread that used a copy constructor on the logger object.
}

I managed to get around the problem by simply assigning "0" to the logger pointer.

The magic trick is located inside log4cxx source code in the file src/main/include/log4cxx/helpers/objectptr.h

That is, releaseRef() giving indirect control over object destruction order.

    ...
    ...
        ObjectPtrT& operator=(const int& null) //throw(IllegalArgumentException)
             {
                    //
                    //   throws IllegalArgumentException if null != 0
                    //
                    ObjectPtrBase::checkNull(null);
                    T* oldPtr = exchange(0);
                    if (oldPtr != 0) {
                       oldPtr->releaseRef();
                    }
                    return *this;
             }
...
...

So, for your code, simply add a line at the end :

#includes<...>
...
...
LoggerPtr logger(Logger::getLogger("MyApp"));

void main(...)
{
    //some logs here

    logger = 0; // RELEASE REFERENCE TO POINTER

   // Make sure no other reference to logger exist
   // ie: a thread that used a copy constructor on the logger object.
}
歌枕肩 2024-12-01 16:41:05

将 LoggerPtr 放入类中可以解决此问题,例如:

class A
{
public:
    A()
    {
           string appPath = getenv("APPDIR");
           appPath = appPath + "/" + LOG4CXX_CONFIG_FILE_NAME;

           // Load configuration file
           DOMConfigurator::configure(appPath.c_str());
           m_serviceLogger = Logger::getLogger("tuxedoService");
    }

    void log()
    {
        LOG4CXX_ERROR(m_serviceLogger, "This is a Test log");
    }

private:
    LoggerPtr m_serviceLogger;
};

A a;
int main()
{ 
   a.log();
   return 0;
}

请注意,如果您将构造函数替换为成员函数(如 init()),并调用 init()在 main 中的日志函数之前,它将导致段错误,正如您再次描述的那样。

这是一个去初始化序列问题。

Putting your LoggerPtr inside of a class can resolve this issue, like:

class A
{
public:
    A()
    {
           string appPath = getenv("APPDIR");
           appPath = appPath + "/" + LOG4CXX_CONFIG_FILE_NAME;

           // Load configuration file
           DOMConfigurator::configure(appPath.c_str());
           m_serviceLogger = Logger::getLogger("tuxedoService");
    }

    void log()
    {
        LOG4CXX_ERROR(m_serviceLogger, "This is a Test log");
    }

private:
    LoggerPtr m_serviceLogger;
};

A a;
int main()
{ 
   a.log();
   return 0;
}

Please note, if you replace constructor with a member function, like init(), and call init() in main before the log function, it will result segment fault as you described again.

This is a deinitialization sequence issue.

吹梦到西洲 2024-12-01 16:41:05

我会在这里用我们遇到的类似案例来插话。我们引用的记录器未在 log4cxx 配置文件中定义。在该库的某些版本中,这很好,但在其他版本中,它会导致堆栈跟踪,如下所示:

Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb) bt
#0  0x0000000000000000 in ?? ()
#1  0x00007ffff72b3892 in std::_Rb_tree<std::string, std::pair<std::string const, log4cxx::helpers::ObjectPtrT<log4cxx::Logger> >, std::_Select1st<std::pair<std::string const, log4cxx::helpers::ObjectPtrT<log4cxx::Logger> > >, std::less<std::string>, std::allocator<std::pair<std::string const, log4cxx::helpers::ObjectPtrT<log4cxx::Logger> > > >::_M_erase(std::_Rb_tree_node<std::pair<std::string const, log4cxx::helpers::ObjectPtrT<log4cxx::Logger> > >*) ()
   from /usr/lib/liblog4cxx.so.10
#2  0x00007ffff72b387b in std::_Rb_tree<std::string, std::pair<std::string const, log4cxx::helpers::ObjectPtrT<log4cxx::Logger> >, std::_Select1st<std::pair<std::string const, log4cxx::helpers::ObjectPtrT<log4cxx::Logger> > >, std::less<std::string>, std::allocator<std::pair<std::string const, log4cxx::helpers::ObjectPtrT<log4cxx::Logger> > > >::_M_erase(std::_Rb_tree_node<std::pair<std::string const, log4cxx::helpers::ObjectPtrT<log4cxx::Logger> > >*) ()
   from /usr/lib/liblog4cxx.so.10
#3  0x00007ffff72b387b in std::_Rb_tree<std::string, std::pair<std::string const, log4cxx::helpers::ObjectPtrT<log4cxx::Logger> >, std::_Select1st<std::pair<std::string const, log4cxx::helpers::ObjectPtrT<log4cxx::Logger> > >, std::less<std::string>, std::allocator<std::pair<std::string const, log4cxx::helpers::ObjectPtrT<log4cxx::Logger> > > >::_M_erase(std::_Rb_tree_node<std::pair<std::string const, log4cxx::helpers::ObjectPtrT<log4cxx::Logger> > >*) ()
   from /usr/lib/liblog4cxx.so.10
#4  0x00007ffff72b1a2a in log4cxx::Hierarchy::~Hierarchy() () from /usr/lib/liblog4cxx.so.10
#5  0x00007ffff72b1c49 in log4cxx::Hierarchy::~Hierarchy() () from /usr/lib/liblog4cxx.so.10
#6  0x00007ffff72c982a in log4cxx::spi::DefaultRepositorySelector::~DefaultRepositorySelector() ()
   from /usr/lib/liblog4cxx.so.10
#7  0x00007ffff72c95bc in log4cxx::helpers::ObjectPtrT<log4cxx::spi::RepositorySelector>::~ObjectPtrT() ()
   from /usr/lib/liblog4cxx.so.10
#8  0x00007ffff52e8e25 in __cxa_finalize () from /lib/x86_64-linux-gnu/libc.so.6
#9  0x00007ffff727c2b6 in ?? () from /usr/lib/liblog4cxx.so.10
#10 0x000000000000005b in ?? ()

因此,我们只需删除引用,一切都很好。这是一个看起来非常无伤大雅的声明:

LoggerPtr logger(Logger::getLogger("someloggerthatdoesnotexist"));

I'll chime in here with a similar case we had. We were referencing a logger that was not defined in our log4cxx configuration file. In some version of the library this was fine, but in others it caused a stack trace as follows:

Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb) bt
#0  0x0000000000000000 in ?? ()
#1  0x00007ffff72b3892 in std::_Rb_tree<std::string, std::pair<std::string const, log4cxx::helpers::ObjectPtrT<log4cxx::Logger> >, std::_Select1st<std::pair<std::string const, log4cxx::helpers::ObjectPtrT<log4cxx::Logger> > >, std::less<std::string>, std::allocator<std::pair<std::string const, log4cxx::helpers::ObjectPtrT<log4cxx::Logger> > > >::_M_erase(std::_Rb_tree_node<std::pair<std::string const, log4cxx::helpers::ObjectPtrT<log4cxx::Logger> > >*) ()
   from /usr/lib/liblog4cxx.so.10
#2  0x00007ffff72b387b in std::_Rb_tree<std::string, std::pair<std::string const, log4cxx::helpers::ObjectPtrT<log4cxx::Logger> >, std::_Select1st<std::pair<std::string const, log4cxx::helpers::ObjectPtrT<log4cxx::Logger> > >, std::less<std::string>, std::allocator<std::pair<std::string const, log4cxx::helpers::ObjectPtrT<log4cxx::Logger> > > >::_M_erase(std::_Rb_tree_node<std::pair<std::string const, log4cxx::helpers::ObjectPtrT<log4cxx::Logger> > >*) ()
   from /usr/lib/liblog4cxx.so.10
#3  0x00007ffff72b387b in std::_Rb_tree<std::string, std::pair<std::string const, log4cxx::helpers::ObjectPtrT<log4cxx::Logger> >, std::_Select1st<std::pair<std::string const, log4cxx::helpers::ObjectPtrT<log4cxx::Logger> > >, std::less<std::string>, std::allocator<std::pair<std::string const, log4cxx::helpers::ObjectPtrT<log4cxx::Logger> > > >::_M_erase(std::_Rb_tree_node<std::pair<std::string const, log4cxx::helpers::ObjectPtrT<log4cxx::Logger> > >*) ()
   from /usr/lib/liblog4cxx.so.10
#4  0x00007ffff72b1a2a in log4cxx::Hierarchy::~Hierarchy() () from /usr/lib/liblog4cxx.so.10
#5  0x00007ffff72b1c49 in log4cxx::Hierarchy::~Hierarchy() () from /usr/lib/liblog4cxx.so.10
#6  0x00007ffff72c982a in log4cxx::spi::DefaultRepositorySelector::~DefaultRepositorySelector() ()
   from /usr/lib/liblog4cxx.so.10
#7  0x00007ffff72c95bc in log4cxx::helpers::ObjectPtrT<log4cxx::spi::RepositorySelector>::~ObjectPtrT() ()
   from /usr/lib/liblog4cxx.so.10
#8  0x00007ffff52e8e25 in __cxa_finalize () from /lib/x86_64-linux-gnu/libc.so.6
#9  0x00007ffff727c2b6 in ?? () from /usr/lib/liblog4cxx.so.10
#10 0x000000000000005b in ?? ()

So we simply had to remove the reference and all was good. It was a very innocuous looking statement:

LoggerPtr logger(Logger::getLogger("someloggerthatdoesnotexist"));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文