Bug #14667
closedSegfault in WebSession destructor
0%
Description
Affected: at least Wt 4.11.4
The segfault occasionally happens when a WebSession is destroyed, for example due to idle timeout expiring or - as in the stacktrace below - when a test finishes.
Successful workaround: do not use WLocale::currentLocale_ as shown in the attached diff
Initial analysis: the bug appears to be the execution order of destructors
~WebSessiontries to write a log line"session destroyed (#sessions = ..."WLogfinds an existing session and callsWebSession::log()WebSession::log()creates aWLogger::Timestampand callsoperator<<(WLogEntry, WLogger::TimeStamp)operator<<(WLogEntry, WLogger::TimeStamp)callsWLocalDateTime::currentServerDateTime()WLocalDateTime::currentServerDateTime()callsWLocale::currentLocale().dateTimeFormat()WLocale::currentLocale()does not find aWApplicationand itslocale(), thus as fallback returns by reference the thread_local variablecurrentLocale_which sometimes is already destroyed
Note: this bug report is entirely manual - no AI was involved.
Stack trace from build with -fsanitize=address -fsanitize-address-use-after-scope -fsanitize=undefined
==1386982==ERROR: AddressSanitizer: heap-use-after-free on address 0x60300069e4a0 at pc 0x7e454dc70fb6 bp 0x7ffd20b60f20 sp 0x7ffd20b606c8
READ of size 19 at 0x60300069e4a0 thread T0
#0 0x7e454dc70fb5 in __interceptor_memcpy ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:899
#1 0x7e454951bb7d in std::char_traits<char>::copy(char*, char const*, unsigned long) /usr/include/c++/13/bits/char_traits.h:445
#2 0x7e454952ee76 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_S_copy(char*, char const*, unsigned long) /usr/include/c++/13/bits/basic_string.h:420
#3 0x7e454953586b in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_S_copy_chars(char*, char*, char*) /usr/include/c++/13/bits/basic_string.h:468
#4 0x7e454953065c in void std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_construct<char*>(char*, char*, std::forward_iterator_tag) /usr/include/c++/13/bits/basic_string.tcc:243
#5 0x7e4549529ff3 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /usr/include/c++/13/bits/basic_string.h:541
#6 0x7e44c2f66021 in Wt::WString::WString(Wt::WString const&) /home/user/wt-4.11.4/src/Wt/WString.C:114
#7 0x7e44c20da9c8 in Wt::WLocale::dateTimeFormat() const /home/user/wt-4.11.4/src/Wt/WLocale.h:191
#8 0x7e44c2956d51 in Wt::WLocalDateTime::currentServerDateTime() /home/user/wt-4.11.4/src/Wt/WLocalDateTime.C:350
#9 0x7e44c2a6b251 in Wt::WLogEntry::operator<<(Wt::WLogger::TimeStamp const&) /home/user/wt-4.11.4/src/Wt/WLogger.C:59
#10 0x7e44c475af43 in Wt::WebSession::log(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) const /home/user/wt-4.11.4/src/web/WebSession.C:234
#11 0x7e44c2a7435a in Wt::log(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /home/user/wt-4.11.4/src/Wt/WLogger.C:454
#12 0x7e44c475d7d4 in Wt::WebSession::~WebSession() /home/user/wt-4.11.4/src/web/WebSession.C:289
#13 0x7e450fb8dc5f in std::_Sp_counted_ptr<Wt::WebSession*, (__gnu_cxx::_Lock_policy)2>::_M_dispose() /usr/include/c++/13/bits/shared_ptr_base.h:428
#14 0x7e450fb7cde0 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release_last_use() /usr/include/c++/13/bits/shared_ptr_base.h:175
#15 0x7e450fb7cc27 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release_last_use_cold() /usr/include/c++/13/bits/shared_ptr_base.h:199
#16 0x7e450fb776f9 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() /usr/include/c++/13/bits/shared_ptr_base.h:353
#17 0x7e450fb7d361 in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count() /usr/include/c++/13/bits/shared_ptr_base.h:1071
#18 0x7e450fb7bd6f in std::__shared_ptr<Wt::WebSession, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr() /usr/include/c++/13/bits/shared_ptr_base.h:1524
#19 0x7e450fb7fb6a in std::__shared_ptr<Wt::WebSession, (__gnu_cxx::_Lock_policy)2>::reset() /usr/include/c++/13/bits/shared_ptr_base.h:1642
#20 0x7e450fb73c79 in Wt::Test::WTestEnvironment::~WTestEnvironment() /home/user/wt-4.11.4/src/Wt/Test/WTestEnvironment.C:141
#21 0x7e44ba845494 (/lib/x86_64-linux-gnu/libc.so.6+0x45494) (BuildId: 4f7b0c955c3d81d7cac1501a2498b69d1d82bfe7)
#22 0x7e44ba84560f in exit (/lib/x86_64-linux-gnu/libc.so.6+0x4560f) (BuildId: 4f7b0c955c3d81d7cac1501a2498b69d1d82bfe7)
#23 0x7e44ba829d96 (/lib/x86_64-linux-gnu/libc.so.6+0x29d96) (BuildId: 4f7b0c955c3d81d7cac1501a2498b69d1d82bfe7)
#24 0x7e44ba829e3f in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e3f) (BuildId: 4f7b0c955c3d81d7cac1501a2498b69d1d82bfe7)
[...]
Here's where currentLocale_ has been previously destroyed, helpfully reported by the sanitizer:
0x60300069e4a0 is located 0 bytes inside of 31-byte region [0x60300069e4a0,0x60300069e4bf)
freed by thread T0 here:
#0 0x7e454dce0c50 in operator delete(void*, unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:164
#1 0x5852778f7be0 in std::__new_allocator<char>::deallocate(char*, unsigned long) /usr/include/c++/13/bits/new_allocator.h:168
#2 0x5852778f6fc5 in std::allocator<char>::deallocate(char*, unsigned long) /usr/include/c++/13/bits/allocator.h:210
#3 0x5852778f6fc5 in std::allocator_traits<std::allocator<char> >::deallocate(std::allocator<char>&, char*, unsigned long) /usr/include/c++/13/bits/alloc_traits.h:516
#4 0x5852778f6fc5 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_destroy(unsigned long) /usr/include/c++/13/bits/basic_string.h:289
#5 0x5852778f69d8 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_dispose() /usr/include/c++/13/bits/basic_string.h:283
#6 0x5852778f6188 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() /usr/include/c++/13/bits/basic_string.h:792
#7 0x7e44c2f66847 in Wt::WString::~WString() /home/user/wt-4.11.4/src/Wt/WString.C:135
#8 0x7e44c20db273 in Wt::WLocale::~WLocale() /home/user/wt-4.11.4/src/Wt/WLocale.h:53
#9 0x7e44ba845d9e in __call_tls_dtors (/lib/x86_64-linux-gnu/libc.so.6+0x45d9e) (BuildId: 4f7b0c955c3d81d7cac1501a2498b69d1d82bfe7)
previously allocated by thread T0 here:
#0 0x7e454dcdfba8 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:95
#1 0x7e45495290c6 in std::__new_allocator<char>::allocate(unsigned long, void const*) /usr/include/c++/13/bits/new_allocator.h:147
#2 0x7e454952553f in std::allocator<char>::allocate(unsigned long) /usr/include/c++/13/bits/allocator.h:198
#3 0x7e454952553f in std::allocator_traits<std::allocator<char> >::allocate(std::allocator<char>&, unsigned long) /usr/include/c++/13/bits/alloc_traits.h:482
#4 0x7e454952553f in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_S_allocate(std::allocator<char>&, unsigned long) /usr/include/c++/13/bits/basic_string.h:126
#5 0x7e45495251bb in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_create(unsigned long&, unsigned long) /usr/include/c++/13/bits/basic_string.tcc:155
#6 0x7e4549534de3 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_mutate(unsigned long, unsigned long, char const*, unsigned long) /usr/include/c++/13/bits/basic_string.tcc:328
#7 0x7e4549537365 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_replace(unsigned long, unsigned long, char const*, unsigned long) /usr/include/c++/13/bits/basic_string.tcc:543
#8 0x7e454960f1de in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::assign(char const*) /usr/include/c++/13/bits/basic_string.h:1672
#9 0x7e45496001e0 in std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::operator=(char const*) /usr/include/c++/13/bits/basic_string.h:812
#10 0x7e44c2f64857 in Wt::WString::WString(char const*, Wt::CharEncoding) /home/user/wt-4.11.4/src/Wt/WString.C:75
#11 0x7e44c29435c4 in Wt::WLocale::WLocale() /home/user/wt-4.11.4/src/Wt/WLocale.C:20
#12 0x7e44c294ab9c in __tls_init /home/user/wt-4.11.4/src/Wt/WLocale.C:11
#13 0x7e44c294abdb in TLS wrapper function for Wt::(anonymous namespace)::currentLocale_ (/home/user/wt-build-sanitized/src/libwt.so.4.11.4+0x714abdb) (BuildId: e61e322ba1107b58d29c44cf88d3a6bd453cab9f)
#14 0x7e44c2945aa9 in Wt::WLocale::currentLocale() /home/user/wt-4.11.4/src/Wt/WLocale.C:98
#15 0x7e44c2956cdb in Wt::WLocalDateTime::currentServerDateTime() /home/user/wt-4.11.4/src/Wt/WLocalDateTime.C:350
#16 0x7e44c2a6b251 in Wt::WLogEntry::operator<<(Wt::WLogger::TimeStamp const&) /home/user/wt-4.11.4/src/Wt/WLogger.C:59
#17 0x7e44c2dfb8a5 in Wt::WServer::log(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) const /home/user/wt-4.11.4/src/Wt/WServer.C:165
#18 0x7e44c2a743cf in Wt::log(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /home/user/wt-4.11.4/src/Wt/WLogger.C:459
#19 0x7e44c4573638 in Wt::Configuration::readConfiguration(bool) /home/user/wt-4.11.4/src/web/Configuration.C:1442
#20 0x7e44c455267f in Wt::Configuration::Configuration(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Wt::WServer*) /home/user/wt-4.11.4/src/web/Configuration.C:252
#21 0x7e44c2dfcea0 in Wt::WServer::configuration() /home/user/wt-4.11.4/src/Wt/WServer.C:199
#22 0x7e44c2df9683 in Wt::WServer::ioService() /home/user/wt-4.11.4/src/Wt/WServer.C:103
#23 0x7e450fb6e6cd in Wt::WServer::WServer(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) /home/user/wt-4.11.4/src/Wt/Test/WTestEnvironment.C:27
#24 0x7e450fb6fca3 in Wt::Test::WTestEnvironment::WTestEnvironment(Wt::EntryPointType) /home/user/wt-4.11.4/src/Wt/Test/WTestEnvironment.C:47
[...]
Files
Updated by Massimiliano Ghilardi about 1 month ago
My (completely subjective) impression is that the thread_local variable currentLocale_ defined in WLocale.C is already a workaround,
added for emulating per-session locales with per-thread locales even when a WApplication is not present:
namespace {
thread_local WLocale currentLocale_;
}
const WLocale& WLocale::currentLocale()
{
WApplication *app = WApplication::instance();
if (app)
return app->locale();
else
return currentLocale_;
}
and
void WLocale::setCurrentLocale(const WLocale &locale)
{
WApplication *app = WApplication::instance();
if (app) {
app->setLocale(locale);
}
else {
currentLocale_ = locale;
}
}
I am not well-versed enough in Wt internals to evaluate the need (or usefulness) of this mechanism, which triggers the bug.
Updated by Romain Mardulyn 29 days ago ยท Edited
- Status changed from New to InProgress
- Assignee set to Romain Mardulyn
- Target version set to 4.14.1
Hi Massimiliano,
We cannot use the fix you proposed because the currentLocale_ variable is used for static WResources , which have no attached WApplication. But I have found another way.
Updated by Romain Mardulyn 29 days ago
- Status changed from InProgress to Review
- Assignee deleted (
Romain Mardulyn)
Updated by emil de keyser 27 days ago
- Status changed from Review to Resolved
- Assignee changed from emil de keyser to Romain Mardulyn
Updated by Romain Mardulyn 23 days ago
- Status changed from Resolved to Implemented @Emweb
Updated by Romain Mardulyn 6 days ago
- Status changed from Implemented @Emweb to Closed