abumq / easyloggingpp

C++ logging library. It is extremely powerful, extendable, light-weight, fast performing, thread and type safe and consists of many built-in features. It provides ability to write logs in your own customized format. It also provide support for logging your classes, third-party libraries, STL and third-party containers etc.
MIT License
3.72k stars 915 forks source link

easylogging throw on HeapAlloc during initialization for static build with thread-safe (windows, vcpkg, static, thread-safe) #842

Open wluter opened 10 months ago

wluter commented 10 months ago

easyloggingpp from vcpkg seems to throw during INITIALIZE_EASYLOGGINGPP when used in a static build on Windows with thread-safe feature enabled. The error involves heap allocation.

It is a 64 bit MFC application on windows with static build and uses vcpkg for several components including easyloggingpp

Stack Trace: ntdll.dll!00007ffb4eabe414() Unknown ntdll.dll!00007ffb4eabb44d() Unknown

MyApp.exe!heap_alloc_dbg_internal(const unsigned int64 size, const int block_use, const char const file_name, const int line_number) Line 359 C++ MyApp.exe!heap_alloc_dbg(const unsigned __int64 size, const int block_use, const char const file_name, const int line_number) Line 450 C++ MyApp.exe!_malloc_dbg(unsigned int64 size, int block_use, const char file_name, int line_number) Line 496 C++ MyApp.exe!operator new(unsigned int64 nSize) Line 43 C++ MyApp.exe!std::_Default_allocate_traits::_Allocate(const unsigned int64 _Bytes) Line 88 C++ MyApp.exe!std::_Allocate<16,std::_Default_allocate_traits,0>(const unsigned __int64 _Bytes) Line 245 C++ MyApp.exe!std::allocator<std::_List_node<std::pair<enum el::Level const ,el::base::LogFormat>,void >>::allocate(const unsigned int64 _Count) Line 975 C++ MyApp.exe!std::_Alloc_construct_ptr<std::allocator<std::_List_node<std::pair<enum el::Level const ,el::base::LogFormat>,void >>>::_Allocate() Line 1152 C++ MyApp.exe!std::_List_node_emplace_op2<std::allocator<std::_List_node<std::pair<enum el::Level const ,el::base::LogFormat>,void >>>::_List_node_emplace_op2<std::allocator<std::_List_node<std::pair<enum el::Level const ,el::base::LogFormat>,void >>><std::pair<enum el::Level,el::base::LogFormat>>(std::allocator<std::_List_node<std::pair<enum el::Level const ,el::base::LogFormat>,void >> & Al, std::pair<enum el::Level,el::base::LogFormat> && <_Vals_0>) Line 586 C++ MyApp.exe!std::_Hash<std::_Umap_traits<enum el::Level,el::base::LogFormat,std::_Uhash_compare<enum el::Level,std::hash,std::equal_to>,std::allocator<std::pair<enum el::Level const ,el::base::LogFormat>>,0>>::emplace<std::pair<enum el::Level,el::base::LogFormat>>(std::pair<enum el::Level,el::base::LogFormat> && <_Vals_0>) Line 613 C++ MyApp.exe!std::unordered_map<enum el::Level,el::base::LogFormat,std::hash,std::equal_to,std::allocator<std::pair<enum el::Level const ,el::base::LogFormat>>>::insert<std::pair<enum el::Level,el::base::LogFormat>,0>(std::pair<enum el::Level,el::base::LogFormat> && _Val) Line 276 C++ MyApp.exe!el::base::TypedConfigurations::setValue(el::Level level, const el::base::LogFormat & value, std::unordered_map<enum el::Level,el::base::LogFormat,std::hash,std::equal_to,std::allocator<std::pair<enum el::Level const ,el::base::LogFormat>>> confMap, bool includeGlobalLevel) Line 2018 C++ MyApp.exe!el::base::TypedConfigurations::build(el::Configurations configurations) Line 1697 C++ MyApp.exe!el::base::TypedConfigurations::TypedConfigurations(el::Configurations configurations, std::shared_ptr<std::unordered_map<std::string,std::shared_ptr<std::basic_fstream<char,std::char_traits>>,std::hash,std::equal_to,std::allocator<std::pair<std::string const ,std::shared_ptr<std::basic_fstream<char,std::char_traits>>>>>> logStreamsReference) Line 1621 C++ MyApp.exe!el::Logger::configure(const el::Configurations & configurations) Line 661 C++ MyApp.exe!el::Logger::Logger(const std::string & id, const el::Configurations & configurations, std::shared_ptr<std::unordered_map<std::string,std::shared_ptr<std::basic_fstream<char,std::char_traits>>,std::hash,std::equal_to,std::allocator<std::pair<std::string const ,std::shared_ptr<std::basic_fstream<char,std::char_traits>>>>>> logStreamsReference) Line 619 C++ MyApp.exe!el::base::RegisteredLoggers::get(const std::string & id, bool forceCreation) Line 1900 C++ MyApp.exe!el::base::Storage::Storage(const std::shared_ptr & defaultLogBuilder) Line 2079 C++ MyApp.exe!el::base::`dynamic initializer for 'elStorage''() Line 19 C++ MyApp.exe!_initterm(void()() first, void()() * last) Line 22 C++ MyApp.exe!scrt_common_main_seh() Line 258 C++ MyApp.exe!scrt_common_main() Line 331 C++ MyApp.exe!wWinMainCRTStartup(void * formal) Line 17 C++ kernel32.dll!00007ffb4e4e7614() Unknown ntdll.dll!00007ffb4eae26f1() Unknown

wluter commented 10 months ago

I have a minimal project ready to demonstrate the problem. Some additional notes: 1) If you compile static with a vcpkg manifest file using no features it compiles, easylogging initializes, and it runs but will eventually crash if you log from multiple threads. 2) If you enable feature no-defaultfile it will not initialize 3) If you enable thread-safe it will not initialize 4) Because MFC application does not expose main() then INITIALIZE_EASYLOGGING must be put in the cpp of the CWinApp derived application class where InitInstance is called. Maybe this is the problem?

wluter commented 10 months ago

Further reading and debugging indicates this may be due to it being a static compilation. The actual HeapAlloc error occurs during creation of el::base::Storage.

To debug I replaced INITIALIZE_EASYLOGGINGPP AS FOLLOWS: //INITIALIZE_EASYLOGGINGPP namespace el { namespace base { el::base::type::StoragePointer elStorage; } el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER); } And put this at the begging of main: el::base::DefaultLogBuilder* dlb = new el::base::DefaultLogBuilder(); el::LogBuilderPtr lpb(dlb); el::base::Storage * s = new el::base::Storage(lpb); //<<< FAILS HERE el::base::elStorage.reset(s); START_EASYLOGGINGPP(argc, argv);

And the trace shows it fails in Logger* RegisteredLoggers::get

impromptu1583 commented 1 month ago

I also have this issue. @wluter did you ever find a solution?

wluter commented 1 month ago

I also have this issue. @wluter did you ever find a solution?

I did not. I ran out of time trying so I moved on to use g3log instead. I have had tremendous success with it so I have abandoned easyloggingpp. NOTE: if you need multiple log files then g3log is more work - it has a single stream sink and you have to create your own sinks for multiple log files.

impromptu1583 commented 1 month ago

Thank you so much! I'll give g3log a try!