diff options
| author | Albrecht Schlosser <albrechts.fltk@online.de> | 2023-12-23 19:48:58 +0100 |
|---|---|---|
| committer | Albrecht Schlosser <albrechts.fltk@online.de> | 2023-12-23 20:05:48 +0100 |
| commit | 016c36c917de79383fb2d81c267faa0829147bdf (patch) | |
| tree | 9de931553e58e885d741dfab901c2b5dc7fb2d8e | |
| parent | f59702e290be9ededeeae9f0e78b422cf359de3f (diff) | |
Fix memory free() mismatch (#875)
This issue was revealed during testing for GitHub Issue #875.
"ERROR: AddressSanitizer: attempting free on address which was not
malloc()-ed", reported by examples/howto-menu-with-images.cxx if
the window object was released at the end of the program, causing
Fl_Menu_::clear() to be called.
The issue was caused by casting all supported label types to
'const char *' which are stored in Fl_Menu_Item::text and then trying
to free() all text strings in Fl_Menu_::clear() under certain
conditions.
Now images and Fl_Multi_Label's are no longer (tried to be) free'd.
| -rw-r--r-- | src/Fl_Menu_.cxx | 29 |
1 files changed, 27 insertions, 2 deletions
diff --git a/src/Fl_Menu_.cxx b/src/Fl_Menu_.cxx index 0d82d92dc..73998ba7e 100644 --- a/src/Fl_Menu_.cxx +++ b/src/Fl_Menu_.cxx @@ -500,8 +500,33 @@ Fl_Menu_* fl_menu_array_owner = 0; */ void Fl_Menu_::clear() { if (alloc) { - if (alloc>1) for (int i = size(); i--;) - if (menu_[i].text) free((void*)menu_[i].text); + + if (alloc > 1) { + + // See GitHub issue #875: we can't release "everything" + // for several reasons. Maybe we can do better if we create + // a new menu system based on Fl_Widget in 1.5.0 or later. + + // Fl_Image's and Fl_Multi_Label's and their linked objects + // can't be released automatically. However, we must take care + // not to free() images or Fl_Multi_Label's because they can + // either be static or are allocated by operator new. + + for (int i = size(); i--;) { + if (!menu_[i].text) + continue; + switch(menu_[i].labeltype_) { + case _FL_IMAGE_LABEL: + break; + case _FL_MULTI_LABEL: + break; + default: + free((void*)menu_[i].text); + break; + } + } + } + if (this == fl_menu_array_owner) fl_menu_array_owner = 0; else |
