Possible memory leak/dangling pointers in Wt::WTabWidget, after removeTab, under some circumstances
Added by Dottor Hell almost 8 years ago
Good evening, I start to excuse myself for possible grammar (and logical) errors, but keep in mind that here it is 03:00 AM. :)
I'm implementing a chat with tabs, which can be added or closed (for example: a private chat between two members, implemented adding a new tab named using the other member name).
To do it I needed both to remove a tab, when the chat was closed, and to check some data to verify if the same tab exists already when creating a new tab is required.
The obvious path that I followed was to connect this code to the closing tab
void ChatTabs::aTabHasBeenClosed(int i)
{
ChatTabs::ChatTabsWidget *w=(ChatTabs::ChatTabsWidget*)tabs->widget(i);
check_pointer_1(w);
tabs->removeTab(w);
delete w;
}
But here we come to the problem in the subject: testing the code with Valgrind, it appears that doing so there are some leaks:
==14675== 727 (280 direct, 447 indirect) bytes in 1 blocks are definitely lost in loss record 250 of 254
==14675== at 0x4C2E0EF: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==14675== by 0x57B4251: Wt::WMenuItem::setContents(Wt::WWidget*, Wt::WMenuItem::LoadPolicy) (WMenuItem.C:129)
==14675== by 0x57B4818: Wt::WMenuItem::create(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Wt::WString const&, Wt::WWidget*, Wt::WMenuItem::LoadPolicy) (WMenuItem.C:85)
==14675== by 0x57B499E: Wt::WMenuItem::WMenuItem(Wt::WString const&, Wt::WWidget*, Wt::WMenuItem::LoadPolicy) (WMenuItem.C:32)
==14675== by 0x584A76D: Wt::WTabWidget::addTab(Wt::WWidget*, Wt::WString const&, Wt::WTabWidget::LoadPolicy) (WTabWidget.C:52)
==14675== by 0x120F6B6: WtGameStyled::ChatTabs::ChatTabsWidget::forConstructor(WideString const&, bool) (ChatTabs.cpp:140)
Where the last line included is my own program calling addtab with this line:
menu_item_=chattabs_.tabs->addTab((ChatTabsWidget*)this, chatname, TabWidget::LazyLoading);
Now, what is interesting is that if I remove the removeTab, the leak disappears
void ChatTabs::aTabHasBeenClosed(int i)
{
ChatTabs::ChatTabsWidget *w=(ChatTabs::ChatTabsWidget*)tabs->widget(i);
check_pointer_1(w);
// tabs->removeTab(w); no more leak!
delete w;
}
The problem, for me, at that point, was that when I loop between the tabs to check if a clone of the one I was going to create was already there, with this code:
// we create it only if it doesn't exist already
check_pointer_1(tabs);
for (int i=0; i<tabs->count(); ++i)
{
ChatTabsWidget *w=(ChatTabsWidget*)tabs->widget(i);
if (w->chatname()==nametab)
{
// it does exist already!
return;
}
}
The tabs were not removed, so "w" might end up being a dangling pointer.
Thus I tried more "creative" solutions, like deleting myself the menu_item, clearing both it and the widget before/after removing the tab and deleting the widget, and so on.
But either the leak was not resolved or the program crashed.
Even if I have written a simple workaround (checking if the tab is hidden, before checking the widget in it), I thought it was anyway a good idea to inform you.
My installed wt is the 3.3.3, in the case this was effectively a bug, and not a mistake on my side, and you have already fixed it.