Dark mode switching for wxCheckBox on Windows 10
Use MSWMakeOwnerDrawn() instead of SetForegroundColour()
Enable and disable owner-draw as needed
Add same dark mode support for wxRadioButton
Correct translation of "Del" key in some languages Use the key name that is used by Windows itself (for example, on its on-screen keyboard as well as an accelerator in its notepad). Closes #26576.
wxMSW: Border handling code cleanup Remove a useless function and some commented-out code. Closes #26580.
Reject out-of-range parent index in cached help book LoadCachedBook reads each index entry's parent back-reference straight from the .cached file and uses it as an index with no check, so a crafted cached file (which can sit inside a .htb help archive opened through AddBook) may result in creating a pointer to data outside the m_index array; that pointer is later dereferenced when the index is sorted at the end of AddBookParam. The change rejects the file when parentShift is negative or larger than the number of index entries loaded so far, matching the existing version and flags checks just above. Also add a small test under tests/html that feeds such a cached stream and confirms it is now refused rather than reading out of bounds. Closes #26577.
Fix leak in wxHtmlHelpData::LoadCachedBook() after previous commit Don't leak wxHtmlHelpDataItem memory, even if the data is invalid. See #26577.
Avoid events being sent to half-destroyed wxWebViewEdge Ensure that the control doesn't get any size/focus events while it's being already destroyed. See #26566.
Fix repaint artifacts in Edge-based wxWebView When an Edge-based wxWebView is a child of a more complex control and that control is hidden and then shown again, artifacts from the old window will appear in the web view window. Fix this by forcing a repaint, in a non-trivial way because the native window optimizes away most attempts to do it, whenever the window is shown. Closes #26566.
Merge branch 'darkmode-switching-checkbox' of github.com:stevecor/wxWidgets Fix dark mode switching for wxCheckBox and wxRadioButton in wxMSW. See #26572.
Fix disabled wxStaticBox text color in dark mode Ensure that the control is redrawn when it's enabled or disabled and fix its drawing in dark mode when it is disabled. Closes #26575.
OSS-Fuzz: Add new fuzzer targets tar operation Add a new OSS-Fuzz fuzzer targeting tar operation, mirroring the existing zip fuzzer. Closes #26579. Signed-off-by: Arthur Chan <arthu...@adalogics.com>
| ... | ... | @@ -98,6 +98,7 @@ set(TEST_GUI_SRC |
| 98 | 98 | image/image.cpp
|
| 99 | 99 | image/imagwebp.cpp
|
| 100 | 100 | image/rawbmp.cpp
|
| 101 | + html/helpdata.cpp
|
|
| 101 | 102 | html/htmlparser.cpp
|
| 102 | 103 | html/htmlwindow.cpp
|
| 103 | 104 | html/htmprint.cpp
|
| ... | ... | @@ -75,9 +75,6 @@ protected: |
| 75 | 75 | // display properties in the control panel, so avoid doing this for them.
|
| 76 | 76 | virtual bool MSWShouldSetDefaultFont() const { return true; }
|
| 77 | 77 | |
| 78 | - // choose the default border for this window
|
|
| 79 | - virtual wxBorder GetDefaultBorder() const override;
|
|
| 80 | - |
|
| 81 | 78 | // return default best size (doesn't really make any sense, override this)
|
| 82 | 79 | virtual wxSize DoGetBestSize() const override;
|
| 83 | 80 |
| ... | ... | @@ -39,6 +39,9 @@ protected: |
| 39 | 39 | // pointers to this class (and protected dtor enforces this).
|
| 40 | 40 | ~wxMSWOwnerDrawnButtonBase() = default;
|
| 41 | 41 | |
| 42 | + // Make the control owner drawn or reset it to normal style.
|
|
| 43 | + void MSWMakeOwnerDrawn(bool ownerDrawn);
|
|
| 44 | + |
|
| 42 | 45 | // Make the control owner drawn if necessary to implement support for the
|
| 43 | 46 | // given foreground colour.
|
| 44 | 47 | void MSWMakeOwnerDrawnIfNecessary(const wxColour& colFg);
|
| ... | ... | @@ -73,9 +76,6 @@ protected: |
| 73 | 76 | |
| 74 | 77 | |
| 75 | 78 | private:
|
| 76 | - // Make the control owner drawn or reset it to normal style.
|
|
| 77 | - void MSWMakeOwnerDrawn(bool ownerDrawn);
|
|
| 78 | - |
|
| 79 | 79 | // Event handlers used to update the appearance of owner drawn button.
|
| 80 | 80 | void OnMouseEnterOrLeave(wxMouseEvent& event);
|
| 81 | 81 | void OnMouseLeft(wxMouseEvent& event);
|
| ... | ... | @@ -100,7 +100,7 @@ private: |
| 100 | 100 | template <class T>
|
| 101 | 101 | class wxMSWOwnerDrawnButton
|
| 102 | 102 | : public T,
|
| 103 | - private wxMSWOwnerDrawnButtonBase
|
|
| 103 | + protected wxMSWOwnerDrawnButtonBase
|
|
| 104 | 104 | {
|
| 105 | 105 | private:
|
| 106 | 106 | typedef T Base;
|
| ... | ... | @@ -68,6 +68,7 @@ protected: |
| 68 | 68 | virtual void
|
| 69 | 69 | MSWDrawButtonBitmap(wxDC& dc, const wxRect& rect, int flags) override;
|
| 70 | 70 | |
| 71 | + virtual void MSWSetDarkOrLightMode(SetMode setmode) override;
|
|
| 71 | 72 | |
| 72 | 73 | private:
|
| 73 | 74 | // common part of all ctors
|
| ... | ... | @@ -78,8 +78,6 @@ public: |
| 78 | 78 | protected:
|
| 79 | 79 | virtual wxWindowList GetCompositeWindowParts() const override;
|
| 80 | 80 | |
| 81 | - virtual void MSWSetDarkOrLightMode(SetMode setmode) override;
|
|
| 82 | - |
|
| 83 | 81 | // return the region with all the windows inside this static box excluded
|
| 84 | 82 | WXHRGN MSWGetRegionWithoutChildren();
|
| 85 | 83 |
| ... | ... | @@ -130,6 +130,8 @@ private: |
| 130 | 130 | |
| 131 | 131 | void OnTopLevelParentIconized(wxIconizeEvent& event);
|
| 132 | 132 | |
| 133 | + void OnShow(wxShowEvent& event);
|
|
| 134 | + |
|
| 133 | 135 | wxDECLARE_DYNAMIC_CLASS(wxWebViewEdge);
|
| 134 | 136 | |
| 135 | 137 | friend class wxWebViewEdgeImpl;
|
| ... | ... | @@ -226,7 +226,7 @@ msgstr "Slet" |
| 226 | 226 | #: ../src/common/accelcmn.cpp:48
|
| 227 | 227 | msgctxt "keyboard key"
|
| 228 | 228 | msgid "Del"
|
| 229 | -msgstr "Slet"
|
|
| 229 | +msgstr "Del"
|
|
| 230 | 230 | |
| 231 | 231 | #: ../src/common/accelcmn.cpp:49
|
| 232 | 232 | msgctxt "keyboard key"
|
| ... | ... | @@ -221,7 +221,7 @@ msgstr "Eliminar" |
| 221 | 221 | #: ../src/common/accelcmn.cpp:48
|
| 222 | 222 | msgctxt "keyboard key"
|
| 223 | 223 | msgid "Del"
|
| 224 | -msgstr "Eliminar"
|
|
| 224 | +msgstr "Supr"
|
|
| 225 | 225 | |
| 226 | 226 | #: ../src/common/accelcmn.cpp:49
|
| 227 | 227 | msgctxt "keyboard key"
|
| ... | ... | @@ -230,10 +230,9 @@ msgid "Delete" |
| 230 | 230 | msgstr "&Törlés"
|
| 231 | 231 | |
| 232 | 232 | #: ../src/common/accelcmn.cpp:48
|
| 233 | -#, fuzzy
|
|
| 234 | 233 | msgctxt "keyboard key"
|
| 235 | 234 | msgid "Del"
|
| 236 | -msgstr "&Törlés"
|
|
| 235 | +msgstr "Del"
|
|
| 237 | 236 | |
| 238 | 237 | #: ../src/common/accelcmn.cpp:49
|
| 239 | 238 | #, fuzzy
|
| ... | ... | @@ -32,6 +32,8 @@ |
| 32 | 32 | #include "wx/html/htmlfilt.h"
|
| 33 | 33 | #include "wx/filename.h"
|
| 34 | 34 | |
| 35 | +#include "wx/private/make_unique.h"
|
|
| 36 | + |
|
| 35 | 37 | #include "wx/arrimpl.cpp"
|
| 36 | 38 | WX_DEFINE_OBJARRAY(wxHtmlBookRecArray)
|
| 37 | 39 | WX_DEFINE_OBJARRAY(wxHtmlHelpDataItems)
|
| ... | ... | @@ -387,15 +389,24 @@ bool wxHtmlHelpData::LoadCachedBook(wxHtmlBookRecord *book, wxInputStream *f) |
| 387 | 389 | m_index.Alloc(newsize);
|
| 388 | 390 | for (i = st; i < newsize; i++)
|
| 389 | 391 | {
|
| 390 | - wxHtmlHelpDataItem *item = new wxHtmlHelpDataItem;
|
|
| 392 | + auto item = std::make_unique<wxHtmlHelpDataItem>();
|
|
| 391 | 393 | item->name = CacheReadString(f);
|
| 392 | 394 | item->page = CacheReadString(f);
|
| 393 | 395 | item->level = CacheReadInt32(f);
|
| 394 | 396 | item->book = book;
|
| 395 | 397 | int parentShift = CacheReadInt32(f);
|
| 396 | 398 | if (parentShift != 0)
|
| 399 | + {
|
|
| 400 | + // parentShift is a back-reference into the index entries loaded so
|
|
| 401 | + // far; it comes straight from the (possibly malicious) .cached file
|
|
| 402 | + // so an out-of-range value would make the subtraction below wrap
|
|
| 403 | + // around and leave item->parent pointing outside m_index, which is
|
|
| 404 | + // later dereferenced when the index is sorted.
|
|
| 405 | + if (parentShift < 0 || (size_t)parentShift > m_index.size())
|
|
| 406 | + return false;
|
|
| 397 | 407 | item->parent = &m_index[m_index.size() - parentShift];
|
| 398 | - m_index.Add(item);
|
|
| 408 | + }
|
|
| 409 | + m_index.Add(item.release());
|
|
| 399 | 410 | }
|
| 400 | 411 | return true;
|
| 401 | 412 | }
|
| ... | ... | @@ -96,11 +96,8 @@ void wxCheckBox::MSWSetDarkOrLightMode(SetMode setmode) |
| 96 | 96 | {
|
| 97 | 97 | wxCheckBoxBase::MSWSetDarkOrLightMode(setmode);
|
| 98 | 98 | |
| 99 | - // The control properly handles switching to dark mode. But when switching
|
|
| 100 | - // to light mode, the text color remains the same. We must explicitly
|
|
| 101 | - // update the color.
|
|
| 102 | - if ( setmode == SetMode::Change )
|
|
| 103 | - SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT));
|
|
| 99 | + // Use owner-draw mode if needed for dark mode or custom text colour
|
|
| 100 | + MSWMakeOwnerDrawn(wxMSWDarkMode::IsActive() || m_hasFgCol);
|
|
| 104 | 101 | }
|
| 105 | 102 | |
| 106 | 103 | // ----------------------------------------------------------------------------
|
| ... | ... | @@ -215,11 +215,6 @@ wxSize wxControl::DoGetBestSize() const |
| 215 | 215 | return FromDIP(wxSize(DEFAULT_ITEM_WIDTH, DEFAULT_ITEM_HEIGHT));
|
| 216 | 216 | }
|
| 217 | 217 | |
| 218 | -wxBorder wxControl::GetDefaultBorder() const
|
|
| 219 | -{
|
|
| 220 | - return wxControlBase::GetDefaultBorder();
|
|
| 221 | -}
|
|
| 222 | - |
|
| 223 | 218 | /* static */ wxVisualAttributes
|
| 224 | 219 | wxControl::GetClassDefaultAttributes(wxWindowVariant variant)
|
| 225 | 220 | {
|
| ... | ... | @@ -29,6 +29,7 @@ |
| 29 | 29 | #endif
|
| 30 | 30 | |
| 31 | 31 | #include "wx/msw/private.h"
|
| 32 | +#include "wx/msw/private/darkmode.h"
|
|
| 32 | 33 | #include "wx/private/window.h"
|
| 33 | 34 | #include "wx/renderer.h"
|
| 34 | 35 | #include "wx/msw/uxtheme.h"
|
| ... | ... | @@ -338,6 +339,14 @@ void wxRadioButton::MSWDrawButtonBitmap(wxDC& dc, const wxRect& rect, int flags) |
| 338 | 339 | wxRendererNative::Get().DrawRadioBitmap(this, dc, rect, flags);
|
| 339 | 340 | }
|
| 340 | 341 | |
| 342 | +void wxRadioButton::MSWSetDarkOrLightMode(SetMode setmode)
|
|
| 343 | +{
|
|
| 344 | + wxRadioButtonBase::MSWSetDarkOrLightMode(setmode);
|
|
| 345 | + |
|
| 346 | + // Use owner-draw mode if needed for dark mode or custom text colour
|
|
| 347 | + MSWMakeOwnerDrawn(wxMSWDarkMode::IsActive() || m_hasFgCol);
|
|
| 348 | +}
|
|
| 349 | + |
|
| 341 | 350 | #if wxUSE_ACCESSIBILITY
|
| 342 | 351 | |
| 343 | 352 | namespace
|
| ... | ... | @@ -95,15 +95,6 @@ bool wxStaticBox::Create(wxWindow *parent, |
| 95 | 95 | return true;
|
| 96 | 96 | }
|
| 97 | 97 | |
| 98 | -void wxStaticBox::MSWSetDarkOrLightMode(SetMode setmode)
|
|
| 99 | -{
|
|
| 100 | - wxStaticBoxBase::MSWSetDarkOrLightMode(setmode);
|
|
| 101 | - |
|
| 102 | - // Static boxes don't seem to have any dark mode support, so just set the
|
|
| 103 | - // foreground colour contrasting with the dark background for them.
|
|
| 104 | - SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT));
|
|
| 105 | -}
|
|
| 106 | - |
|
| 107 | 98 | bool wxStaticBox::ShouldUseCustomPaint() const
|
| 108 | 99 | {
|
| 109 | 100 | // When not using double buffering, we paint the box ourselves by default
|
| ... | ... | @@ -293,7 +284,11 @@ bool wxStaticBox::SetFont(const wxFont& font) |
| 293 | 284 | |
| 294 | 285 | WXLRESULT wxStaticBox::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
|
| 295 | 286 | {
|
| 296 | - if ( nMsg == WM_NCHITTEST )
|
|
| 287 | + if ( nMsg == WM_ENABLE )
|
|
| 288 | + {
|
|
| 289 | + Refresh();
|
|
| 290 | + }
|
|
| 291 | + else if ( nMsg == WM_NCHITTEST )
|
|
| 297 | 292 | {
|
| 298 | 293 | // This code breaks some other processing such as enter/leave tracking
|
| 299 | 294 | // so it's off by default.
|
| ... | ... | @@ -314,8 +309,7 @@ WXLRESULT wxStaticBox::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lPar |
| 314 | 309 | return (long)HTCLIENT;
|
| 315 | 310 | }
|
| 316 | 311 | }
|
| 317 | - |
|
| 318 | - if ( nMsg == WM_PRINTCLIENT )
|
|
| 312 | + else if ( nMsg == WM_PRINTCLIENT )
|
|
| 319 | 313 | {
|
| 320 | 314 | // we have to process WM_PRINTCLIENT ourselves as otherwise child
|
| 321 | 315 | // windows' background (eg buttons in radio box) would never be drawn
|
| ... | ... | @@ -582,7 +576,8 @@ void wxStaticBox::PaintForeground(wxDC& dc, const RECT&) |
| 582 | 576 | // background mode changes anything: the static box def window proc
|
| 583 | 577 | // still draws the label in its own colours, so we need to redraw the text
|
| 584 | 578 | // ourselves if we have a non default fg colour
|
| 585 | - if ( m_hasFgCol && wxUxThemeIsActive() && !m_labelWin && !GetLabel().empty() )
|
|
| 579 | + if ( (m_hasFgCol || wxMSWDarkMode::IsActive()) && wxUxThemeIsActive() &&
|
|
| 580 | + !m_labelWin && !GetLabel().empty() )
|
|
| 586 | 581 | {
|
| 587 | 582 | // draw over the text in default colour in our colour
|
| 588 | 583 | HDC hdc = GetHdcOf(*impl);
|
| ... | ... | @@ -1127,9 +1127,12 @@ wxWebViewEdge::wxWebViewEdge(wxWindow* parent, |
| 1127 | 1127 | |
| 1128 | 1128 | wxWebViewEdge::~wxWebViewEdge()
|
| 1129 | 1129 | {
|
| 1130 | + Unbind(wxEVT_SIZE, &wxWebViewEdge::OnSize, this);
|
|
| 1131 | + Unbind(wxEVT_SET_FOCUS, &wxWebViewEdge::OnSetFocus, this);
|
|
| 1130 | 1132 | wxWindow* topLevelParent = wxGetTopLevelParent(this);
|
| 1131 | 1133 | if (topLevelParent)
|
| 1132 | 1134 | topLevelParent->Unbind(wxEVT_ICONIZE, &wxWebViewEdge::OnTopLevelParentIconized, this);
|
| 1135 | + Unbind(wxEVT_SHOW, &wxWebViewEdge::OnShow, this);
|
|
| 1133 | 1136 | delete m_impl;
|
| 1134 | 1137 | }
|
| 1135 | 1138 | |
| ... | ... | @@ -1157,6 +1160,7 @@ bool wxWebViewEdge::Create(wxWindow* parent, |
| 1157 | 1160 | wxWindow* topLevelParent = wxGetTopLevelParent(this);
|
| 1158 | 1161 | if (topLevelParent)
|
| 1159 | 1162 | topLevelParent->Bind(wxEVT_ICONIZE, &wxWebViewEdge::OnTopLevelParentIconized, this);
|
| 1163 | + Bind(wxEVT_SHOW, &wxWebViewEdge::OnShow, this);
|
|
| 1160 | 1164 | |
| 1161 | 1165 | LoadURL(url);
|
| 1162 | 1166 | return true;
|
| ... | ... | @@ -1182,6 +1186,27 @@ void wxWebViewEdge::OnTopLevelParentIconized(wxIconizeEvent& event) |
| 1182 | 1186 | event.Skip();
|
| 1183 | 1187 | }
|
| 1184 | 1188 | |
| 1189 | +void wxWebViewEdge::OnShow(wxShowEvent& event)
|
|
| 1190 | +{
|
|
| 1191 | + if ( m_impl && m_impl->m_webViewController )
|
|
| 1192 | + {
|
|
| 1193 | + m_impl->m_webViewController->put_IsVisible(event.IsShown());
|
|
| 1194 | + // Force a refresh by refreshing its paint area
|
|
| 1195 | + if ( event.IsShown() )
|
|
| 1196 | + {
|
|
| 1197 | + // put_Bounds is a no-op when the rect is unchanged, so collapse to
|
|
| 1198 | + // zero first to guarantee a bounds change that forces a repaint
|
|
| 1199 | + m_impl->m_webViewController->put_Bounds(RECT{});
|
|
| 1200 | + CallAfter([this]
|
|
| 1201 | + {
|
|
| 1202 | + if ( m_impl && m_impl->m_webViewController )
|
|
| 1203 | + m_impl->UpdateBounds();
|
|
| 1204 | + });
|
|
| 1205 | + }
|
|
| 1206 | + }
|
|
| 1207 | + event.Skip();
|
|
| 1208 | +}
|
|
| 1209 | + |
|
| 1185 | 1210 | void wxWebViewEdge::LoadURL(const wxString& url)
|
| 1186 | 1211 | {
|
| 1187 | 1212 | if (!m_impl->m_webView)
|
| ... | ... | @@ -1552,10 +1552,6 @@ WXDWORD wxWindowMSW::MSWGetStyle(long flags, WXDWORD *exstyle) const |
| 1552 | 1552 | *exstyle |= WS_EX_CLIENTEDGE;
|
| 1553 | 1553 | style &= ~WS_BORDER;
|
| 1554 | 1554 | break;
|
| 1555 | - |
|
| 1556 | -// case wxBORDER_DOUBLE:
|
|
| 1557 | -// *exstyle |= WS_EX_DLGMODALFRAME;
|
|
| 1558 | -// break;
|
|
| 1559 | 1555 | }
|
| 1560 | 1556 | |
| 1561 | 1557 | // wxUniv doesn't use Windows dialog navigation functions at all
|
| ... | ... | @@ -263,6 +263,7 @@ TEST_GUI_OBJECTS = \ |
| 263 | 263 | test_gui_image.o \
|
| 264 | 264 | test_gui_imagwebp.o \
|
| 265 | 265 | test_gui_rawbmp.o \
|
| 266 | + test_gui_helpdata.o \
|
|
| 266 | 267 | test_gui_htmlparser.o \
|
| 267 | 268 | test_gui_htmlwindow.o \
|
| 268 | 269 | test_gui_htmprint.o \
|
| ... | ... | @@ -1212,6 +1213,9 @@ test_gui_imagwebp.o: $(srcdir)/image/imagwebp.cpp $(TEST_GUI_ODEP) |
| 1212 | 1213 | test_gui_rawbmp.o: $(srcdir)/image/rawbmp.cpp $(TEST_GUI_ODEP)
|
| 1213 | 1214 | $(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/image/rawbmp.cpp
|
| 1214 | 1215 | |
| 1216 | +test_gui_helpdata.o: $(srcdir)/html/helpdata.cpp $(TEST_GUI_ODEP)
|
|
| 1217 | + $(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/html/helpdata.cpp
|
|
| 1218 | + |
|
| 1215 | 1219 | test_gui_htmlparser.o: $(srcdir)/html/htmlparser.cpp $(TEST_GUI_ODEP)
|
| 1216 | 1220 | $(CXXC) -c -o $@ $(TEST_GUI_CXXFLAGS) $(srcdir)/html/htmlparser.cpp
|
| 1217 | 1221 |
| ... | ... | @@ -8,5 +8,10 @@ make -j$(nproc) |
| 8 | 8 | $CXX $CXXFLAGS -o $OUT/zip tests/fuzz/zip.cpp \
|
| 9 | 9 | $LIB_FUZZING_ENGINE `./wx-config --cxxflags --libs base`
|
| 10 | 10 | |
| 11 | +$CXX $CXXFLAGS -o $OUT/tar tests/fuzz/tar.cpp \
|
|
| 12 | + $LIB_FUZZING_ENGINE `./wx-config --cxxflags --libs base`
|
|
| 13 | +cp tests/fuzz/tar.options $OUT/
|
|
| 14 | + |
|
| 11 | 15 | # and copy their corpora
|
| 12 | 16 | zip -j $OUT/zip_seed_corpus.zip tests/fuzz/corpus/zip/*
|
| 17 | +zip -j $OUT/tar_seed_corpus.zip tests/fuzz/corpus/tar/* |
| 1 | +///////////////////////////////////////////////////////////////////////////////
|
|
| 2 | +// Name: tests/fuzz/tar.cpp
|
|
| 3 | +// Purpose: TAR archives reading code fuzzing test
|
|
| 4 | +// Author: Arthur Chan
|
|
| 5 | +// Created: 2026-06-11
|
|
| 6 | +// Copyright: (c) 2026 Arthur Chan
|
|
| 7 | +///////////////////////////////////////////////////////////////////////////////
|
|
| 8 | + |
|
| 9 | +#include "wx/log.h"
|
|
| 10 | +#include "wx/mstream.h"
|
|
| 11 | +#include "wx/tarstrm.h"
|
|
| 12 | + |
|
| 13 | +#if wxDEBUG_LEVEL
|
|
| 14 | + |
|
| 15 | +static void exitAssertHandler(const wxString& file,
|
|
| 16 | + int line,
|
|
| 17 | + const wxString& func,
|
|
| 18 | + const wxString& cond,
|
|
| 19 | + const wxString& msg);
|
|
| 20 | + |
|
| 21 | +static volatile wxAssertHandler_t
|
|
| 22 | + origAssertHandler = wxSetAssertHandler(exitAssertHandler);
|
|
| 23 | + |
|
| 24 | +static void exitAssertHandler(const wxString& file,
|
|
| 25 | + int line,
|
|
| 26 | + const wxString& func,
|
|
| 27 | + const wxString& cond,
|
|
| 28 | + const wxString& msg)
|
|
| 29 | +{
|
|
| 30 | + origAssertHandler(file, line, func, cond, msg);
|
|
| 31 | + |
|
| 32 | + exit(1);
|
|
| 33 | +}
|
|
| 34 | + |
|
| 35 | +#endif // wxDEBUG_LEVEL
|
|
| 36 | + |
|
| 37 | +extern "C" int LLVMFuzzerTestOneInput(const wxUint8 *data, size_t size)
|
|
| 38 | +{
|
|
| 39 | + wxLogNull noLog;
|
|
| 40 | + |
|
| 41 | + wxMemoryInputStream mis(data, size);
|
|
| 42 | + wxTarInputStream tis(mis);
|
|
| 43 | + while ( wxTarEntry* const te = tis.GetNextEntry() ) {
|
|
| 44 | + if ( tis.OpenEntry(*te) ) {
|
|
| 45 | + // Read the entry data to exercise the size/offset parsing and OnSysRead
|
|
| 46 | + char buf[4096];
|
|
| 47 | + while ( tis.IsOk() && !tis.Eof() ) {
|
|
| 48 | + tis.Read(buf, sizeof(buf));
|
|
| 49 | + if ( tis.LastRead() == 0 )
|
|
| 50 | + break;
|
|
| 51 | + }
|
|
| 52 | + tis.CloseEntry();
|
|
| 53 | + }
|
|
| 54 | + delete te;
|
|
| 55 | + }
|
|
| 56 | + |
|
| 57 | + return 0;
|
|
| 58 | +} |
| 1 | +[libfuzzer]
|
|
| 2 | +max_len = 65536 |
| 1 | +///////////////////////////////////////////////////////////////////////////////
|
|
| 2 | +// Name: tests/html/helpdata.cpp
|
|
| 3 | +// Purpose: wxHtmlHelpData tests
|
|
| 4 | +// Author: dxbjavid
|
|
| 5 | +// Copyright: (c) 2026 wxWidgets dev team
|
|
| 6 | +///////////////////////////////////////////////////////////////////////////////
|
|
| 7 | + |
|
| 8 | +// ----------------------------------------------------------------------------
|
|
| 9 | +// headers
|
|
| 10 | +// ----------------------------------------------------------------------------
|
|
| 11 | + |
|
| 12 | +#include "testprec.h"
|
|
| 13 | + |
|
| 14 | +#if wxUSE_HTML
|
|
| 15 | + |
|
| 16 | +#include "wx/html/helpdata.h"
|
|
| 17 | +#include "wx/mstream.h"
|
|
| 18 | + |
|
| 19 | +#include <cstring>
|
|
| 20 | + |
|
| 21 | +namespace
|
|
| 22 | +{
|
|
| 23 | + |
|
| 24 | +// helpers writing the .cached binary help book format exactly the way
|
|
| 25 | +// wxHtmlHelpData::SaveCachedBook() does, so the stream we build is what
|
|
| 26 | +// LoadCachedBook() expects to read
|
|
| 27 | + |
|
| 28 | +void CacheWriteInt32(wxMemoryOutputStream& s, wxInt32 value)
|
|
| 29 | +{
|
|
| 30 | + wxInt32 x = wxINT32_SWAP_ON_BE(value);
|
|
| 31 | + s.Write(&x, sizeof(x));
|
|
| 32 | +}
|
|
| 33 | + |
|
| 34 | +void CacheWriteString(wxMemoryOutputStream& s, const char* str)
|
|
| 35 | +{
|
|
| 36 | + const size_t len = strlen(str) + 1;
|
|
| 37 | + CacheWriteInt32(s, (wxInt32)len);
|
|
| 38 | + s.Write(str, len);
|
|
| 39 | +}
|
|
| 40 | + |
|
| 41 | +// expose the protected loader
|
|
| 42 | +class TestHelpData : public wxHtmlHelpData
|
|
| 43 | +{
|
|
| 44 | +public:
|
|
| 45 | + bool DoLoadCachedBook(wxHtmlBookRecord* book, wxInputStream& f)
|
|
| 46 | + {
|
|
| 47 | + return LoadCachedBook(book, &f);
|
|
| 48 | + }
|
|
| 49 | +};
|
|
| 50 | + |
|
| 51 | +} // anonymous namespace
|
|
| 52 | + |
|
| 53 | +// A crafted .cached file whose single index entry carries a parent
|
|
| 54 | +// back-reference pointing outside the index must be rejected and must not
|
|
| 55 | +// read out of bounds (it previously did, see helpdata.cpp:LoadCachedBook).
|
|
| 56 | +TEST_CASE("wxHtmlHelpData::BadCachedParent", "[html][help][error]")
|
|
| 57 | +{
|
|
| 58 | + wxMemoryOutputStream os;
|
|
| 59 | + CacheWriteInt32(os, 5); // CURRENT_CACHED_BOOK_VERSION
|
|
| 60 | + CacheWriteInt32(os, 1); // CACHED_BOOK_FORMAT_FLAGS
|
|
| 61 | + |
|
| 62 | + CacheWriteInt32(os, 0); // contents count
|
|
| 63 | + |
|
| 64 | + CacheWriteInt32(os, 1); // index count
|
|
| 65 | + CacheWriteString(os, "name");
|
|
| 66 | + CacheWriteString(os, "page.htm");
|
|
| 67 | + CacheWriteInt32(os, 1); // level
|
|
| 68 | + CacheWriteInt32(os, 1000000); // parentShift, way past the index size
|
|
| 69 | + |
|
| 70 | + wxStreamBuffer* buf = os.GetOutputStreamBuffer();
|
|
| 71 | + wxMemoryInputStream is(buf->GetBufferStart(), buf->GetIntPosition());
|
|
| 72 | + |
|
| 73 | + wxHtmlBookRecord book("test.hhp", "", "Test", "page.htm");
|
|
| 74 | + TestHelpData data;
|
|
| 75 | + |
|
| 76 | + // before the fix this indexes m_index out of bounds; with it the file is
|
|
| 77 | + // simply rejected
|
|
| 78 | + CHECK( !data.DoLoadCachedBook(&book, is) );
|
|
| 79 | +}
|
|
| 80 | + |
|
| 81 | +#endif // wxUSE_HTML |
| ... | ... | @@ -283,6 +283,7 @@ |
| 283 | 283 | image/image.cpp
|
| 284 | 284 | image/imagwebp.cpp
|
| 285 | 285 | image/rawbmp.cpp
|
| 286 | + html/helpdata.cpp
|
|
| 286 | 287 | html/htmlparser.cpp
|
| 287 | 288 | html/htmlwindow.cpp
|
| 288 | 289 | html/htmprint.cpp
|
—
View it on GitLab.
You're receiving this email because of your account on gitlab.com. Manage all notifications · Help