Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Shutdown of log4cplus uses static initializer, Thread pool has memory leak #646

@rekib66

Description

@rekib66

Hi,

I use log4cplus 2.0.2 compiled with --disable-implicit-initialization. To test I worte a test program initializing log4cplus, calling two times LOG4CPLUS_INFO and deinitialize log4cplus. To check for memory leaks I run the program using valgrind. In addition I added some printf to ThreadPool.h and global-init.cxx for a better understanding.

I see that even though the source was compiled with --disable-implicit-initialization, static initialization still occurs. The second issue is the findings of valgrind.
Please find my test program and the valgrind / test program output below.
Regards.

#include <stdio.h>
  
#include <log4cplus/clogger.h>
#include <log4cplus/initializer.h>
#include <log4cplus/configurator.h>
#include <log4cplus/hierarchy.h>
#include <log4cplus/loggingmacros.h>

#include <string>

using namespace std;

#define LOGGER_NAME "log4cplustest"

log4cplus::Initializer* log4cplusInstance = 0;
log4cplus::Logger rootLogger;

void initLogger(const string& loggerName) {
  // get config file
  string configFile = loggerName + ".properties";

  // read new config
  log4cplus::PropertyConfigurator config(configFile,
   log4cplus::Logger::getDefaultHierarchy(),
   log4cplus::PropertyConfigurator::fAllowEmptyVars);

  // apply new config
  log4cplus::Logger::getRoot().getHierarchy().resetConfiguration();
  config.configure();
  rootLogger = log4cplus::Logger::getInstance(loggerName);
  LOG4CPLUS_INFO_FMT(LOGGER_NAME, "logging initialized for %s", loggerName.c_str());
}

void openLogFile() {
  log4cplusInstance = new log4cplus::Initializer();
  rootLogger = log4cplus::Logger::getRoot();

  initLogger(LOGGER_NAME);
}

void closeLogFile() {
  delete log4cplusInstance;
}

int main(int , char** , char** ) {
  openLogFile();

  LOG4CPLUS_INFO(LOGGER_NAME, "Started.");

  LOG4CPLUS_INFO(LOGGER_NAME, "Done.");

  closeLogFile();

  return 0;
}
$ /opt/valgrind/bin/valgrind log4cplustest
==1831446== Memcheck, a memory error detector
==1831446== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==1831446== Using Valgrind-3.22.0 and LibVEX; rerun with -h for copyright info
==1831446== Command: log4cplustest
==1831446== 
alloc_dc(): Created DefaultContext 0x64bcb90
ThreadPool::ThreadPool: 0x64c8630, pool_size: 4
ThreadPool::start_worker: workers.push_back() 0
ThreadPool::start_worker: workers.push_back() 1
ThreadPool::start_worker: workers.push_back() 2
ThreadPool::start_worker: workers.push_back() 3
DefaultContext::shutdown_thread_pool(): Calling delete of thread_pool 0x64c8630
ThreadPool::~ThreadPool: 0x64c8630
ThreadPool::start_worker(): stop: t, tasks: 0, worker_number: 3
ThreadPool::start_worker(): stop: t, tasks: 0, worker_number: 0
ThreadPool::start_worker(): stop: t, tasks: 0, worker_number: 2
ThreadPool::start_worker(): stop: t, tasks: 0, worker_number: 1
ThreadPool::start_worker(): workers vector empty. worker_number: 1
~Initializer(): Calling delete InitializerImpl::instance 0x64bbd90
destroy_default_context::~destroy_default_context(): Calling delete default_context 0x64bcb90
ThreadPoolHolder::~ThreadPoolHolder(): Calling delete of thread_pool (nil)
threadCleanup(): Calling delete ptd 0x64bbe50
==1831446== 
==1831446== HEAP SUMMARY:
==1831446==     in use at exit: 632 bytes in 3 blocks
==1831446==   total heap usage: 616 allocs, 613 frees, 133,939 bytes allocated
==1831446== 
==1831446== 24 bytes in 1 blocks are still reachable in loss record 1 of 2
==1831446==    at 0x4C327EF: operator new(unsigned long) (vg_replace_malloc.c:483)
==1831446==    by 0x4F1A330: std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> > std::thread::_S_make_state<std::thread::_Invoker<std::tuple<progschj::ThreadPool::start_worker(unsigned long, std::unique_lock<std::mutex> const&)::{lambda()#1}> > >(std::thread::_Invoker<std::tuple<progschj::ThreadPool::start_worker(unsigned long, std::unique_lock<std::mutex> const&)::{lambda()#1}> >&&) (thread:207)
==1831446==    by 0x4F18C9E: std::thread::thread<progschj::ThreadPool::start_worker(unsigned long, std::unique_lock<std::mutex> const&)::{lambda()#1}&, , void>(progschj::ThreadPool::start_worker(unsigned long, std::unique_lock<std::mutex> const&)::{lambda()#1}&) (thread:131)
==1831446==    by 0x4F1790C: progschj::ThreadPool::start_worker(unsigned long, std::unique_lock<std::mutex> const&) (ThreadPool.h:342)
==1831446==    by 0x4F16EF2: progschj::ThreadPool::ThreadPool(unsigned long) (ThreadPool.h:134)
==1831446==    by 0x4F0F31E: log4cplus::(anonymous namespace)::instantiate_thread_pool() (global-init.cxx:145)
==1831446==    by 0x4F0F404: log4cplus::(anonymous namespace)::DefaultContext::get_thread_pool(bool)::{lambda()#1}::operator()() const (global-init.cxx:201)
==1831446==    by 0x4F113A4: void std::__invoke_impl<void, log4cplus::(anonymous namespace)::DefaultContext::get_thread_pool(bool)::{lambda()#1}>(std::__invoke_other, log4cplus::(anonymous namespace)::DefaultContext::get_thread_pool(bool)::{lambda()#1}&&) (invoke.h:60)
==1831446==    by 0x4F10BA3: std::__invoke_result<log4cplus::(anonymous namespace)::DefaultContext::get_thread_pool(bool)::{lambda()#1}>::type std::__invoke<log4cplus::(anonymous namespace)::DefaultContext::get_thread_pool(bool)::{lambda()#1}>(log4cplus::(anonymous namespace)::DefaultContext::get_thread_pool(bool)::{lambda()#1}&&) (invoke.h:95)
==1831446==    by 0x4F109BA: std::call_once<log4cplus::(anonymous namespace)::DefaultContext::get_thread_pool(bool)::{lambda()#1}>(std::once_flag&, log4cplus::(anonymous namespace)::DefaultContext::get_thread_pool(bool)::{lambda()#1}&&)::{lambda()#1}::operator()() const (mutex:672)
==1831446==    by 0x4F109E4: std::call_once<log4cplus::(anonymous namespace)::DefaultContext::get_thread_pool(bool)::{lambda()#1}>(std::once_flag&, log4cplus::(anonymous namespace)::DefaultContext::get_thread_pool(bool)::{lambda()#1}&&)::{lambda()#2}::operator()() const (mutex:677)
==1831446==    by 0x4F109F5: std::call_once<log4cplus::(anonymous namespace)::DefaultContext::get_thread_pool(bool)::{lambda()#1}>(std::once_flag&, log4cplus::(anonymous namespace)::DefaultContext::get_thread_pool(bool)::{lambda()#1}&&)::{lambda()#2}::_FUN() (mutex:677)
==1831446==    by 0x6299CD6: __pthread_once_slow (in /usr/lib64/libpthread-2.28.so)
==1831446==    by 0x4F0F0F6: __gthread_once(int*, void (*)()) (gthr-default.h:699)
==1831446==    by 0x4F10A7B: void std::call_once<log4cplus::(anonymous namespace)::DefaultContext::get_thread_pool(bool)::{lambda()#1}>(std::once_flag&, log4cplus::(anonymous namespace)::DefaultContext::get_thread_pool(bool)::{lambda()#1}&&) (mutex:684)
==1831446== 
==1831446== 608 bytes in 2 blocks are possibly lost in loss record 2 of 2
==1831446==    at 0x4C396D7: calloc (vg_replace_malloc.c:1595)
==1831446==    by 0x4012421: allocate_dtv (in /usr/lib64/ld-2.28.so)
==1831446==    by 0x4012DB1: _dl_allocate_tls (in /usr/lib64/ld-2.28.so)
==1831446==    by 0x6292DA2: pthread_create@@GLIBC_2.2.5 (in /usr/lib64/libpthread-2.28.so)
==1831446==    by 0x5452E88: std::thread::_M_start_thread(std::unique_ptr<std::thread::_State, std::default_delete<std::thread::_State> >, void (*)()) (in /usr/lib64/libstdc++.so.6.0.25)
==1831446==    by 0x4F18CB5: std::thread::thread<progschj::ThreadPool::start_worker(unsigned long, std::unique_lock<std::mutex> const&)::{lambda()#1}&, , void>(progschj::ThreadPool::start_worker(unsigned long, std::unique_lock<std::mutex> const&)::{lambda()#1}&) (thread:131)
==1831446==    by 0x4F1790C: progschj::ThreadPool::start_worker(unsigned long, std::unique_lock<std::mutex> const&) (ThreadPool.h:342)
==1831446==    by 0x4F16EF2: progschj::ThreadPool::ThreadPool(unsigned long) (ThreadPool.h:134)
==1831446==    by 0x4F0F31E: log4cplus::(anonymous namespace)::instantiate_thread_pool() (global-init.cxx:145)
==1831446==    by 0x4F0F404: log4cplus::(anonymous namespace)::DefaultContext::get_thread_pool(bool)::{lambda()#1}::operator()() const (global-init.cxx:201)
==1831446==    by 0x4F113A4: void std::__invoke_impl<void, log4cplus::(anonymous namespace)::DefaultContext::get_thread_pool(bool)::{lambda()#1}>(std::__invoke_other, log4cplus::(anonymous namespace)::DefaultContext::get_thread_pool(bool)::{lambda()#1}&&) (invoke.h:60)
==1831446==    by 0x4F10BA3: std::__invoke_result<log4cplus::(anonymous namespace)::DefaultContext::get_thread_pool(bool)::{lambda()#1}>::type std::__invoke<log4cplus::(anonymous namespace)::DefaultContext::get_thread_pool(bool)::{lambda()#1}>(log4cplus::(anonymous namespace)::DefaultContext::get_thread_pool(bool)::{lambda()#1}&&) (invoke.h:95)
==1831446==    by 0x4F109BA: std::call_once<log4cplus::(anonymous namespace)::DefaultContext::get_thread_pool(bool)::{lambda()#1}>(std::once_flag&, log4cplus::(anonymous namespace)::DefaultContext::get_thread_pool(bool)::{lambda()#1}&&)::{lambda()#1}::operator()() const (mutex:672)
==1831446==    by 0x4F109E4: std::call_once<log4cplus::(anonymous namespace)::DefaultContext::get_thread_pool(bool)::{lambda()#1}>(std::once_flag&, log4cplus::(anonymous namespace)::DefaultContext::get_thread_pool(bool)::{lambda()#1}&&)::{lambda()#2}::operator()() const (mutex:677)
==1831446==    by 0x4F109F5: std::call_once<log4cplus::(anonymous namespace)::DefaultContext::get_thread_pool(bool)::{lambda()#1}>(std::once_flag&, log4cplus::(anonymous namespace)::DefaultContext::get_thread_pool(bool)::{lambda()#1}&&)::{lambda()#2}::_FUN() (mutex:677)
==1831446== 
==1831446== LEAK SUMMARY:
==1831446==    definitely lost: 0 bytes in 0 blocks
==1831446==    indirectly lost: 0 bytes in 0 blocks
==1831446==      possibly lost: 608 bytes in 2 blocks
==1831446==    still reachable: 24 bytes in 1 blocks
==1831446==         suppressed: 0 bytes in 0 blocks
==1831446== 
==1831446== For lists of detected and suppressed errors, rerun with: -s
==1831446== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions