[Git][wxwidgets/wxwidgets][master] 13 commits: Dark mode switching for wxCheckBox on Windows 10

2 views
Skip to first unread message

Vadim Zeitlin (@_VZ_)

unread,
Jun 11, 2026, 6:07:13 PMJun 11
to wx-commi...@googlegroups.com

Vadim Zeitlin pushed to branch master at wxWidgets / wxWidgets

Commits:

  • 063f78f6
    by Steve Cornett at 2026-06-08T10:14:01-07:00
    Dark mode switching for wxCheckBox on Windows 10
    
  • a014ea5f
    by Steve Cornett at 2026-06-10T09:32:52-07:00
    Use MSWMakeOwnerDrawn() instead of SetForegroundColour()
    
  • 04c345d5
    by Steve Cornett at 2026-06-10T16:34:37-07:00
    Enable and disable owner-draw as needed
    
  • ad3b42ad
    by Steve Cornett at 2026-06-10T16:36:11-07:00
    Add same dark mode support for wxRadioButton
    
  • 4fa58636
    by taler21 at 2026-06-11T23:12:25+02:00
    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.
    
  • 2d07a1e2
    by Steve Cornett at 2026-06-11T23:16:52+02:00
    wxMSW: Border handling code cleanup
    
    Remove a useless function and some commented-out code.
    
    Closes #26580.
    
  • ebd86dee
    by dxbjavid at 2026-06-11T23:40:20+02:00
    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.
    
  • 767e9c8b
    by Vadim Zeitlin at 2026-06-11T23:45:37+02:00
    Fix leak in wxHtmlHelpData::LoadCachedBook() after previous commit
    
    Don't leak wxHtmlHelpDataItem memory, even if the data is invalid.
    
    See #26577.
    
  • 6f24da90
    by Blake-Madden at 2026-06-11T23:47:46+02:00
    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.
    
  • 9f397d59
    by Blake-Madden at 2026-06-11T23:48:36+02:00
    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.
    
  • 57def0bc
    by Vadim Zeitlin at 2026-06-11T23:50:50+02:00
    Merge branch 'darkmode-switching-checkbox' of github.com:stevecor/wxWidgets
    
    Fix dark mode switching for wxCheckBox and wxRadioButton in wxMSW.
    
    See #26572.
    
  • 34a29a15
    by Steve Cornett at 2026-06-11T23:52:30+02:00
    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.
    
  • aef89c0e
    by Arthur Chan at 2026-06-11T23:57:23+02:00
    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>
    

23 changed files:

Changes:

  • build/cmake/tests/gui/CMakeLists.txt
    ... ... @@ -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
    

  • include/wx/msw/control.h
    ... ... @@ -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
     
    

  • include/wx/msw/ownerdrawnbutton.h
    ... ... @@ -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;
    

  • include/wx/msw/radiobut.h
    ... ... @@ -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
    

  • include/wx/msw/statbox.h
    ... ... @@ -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
     
    

  • include/wx/msw/webview_edge.h
    ... ... @@ -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;
    

  • locale/da.po
    ... ... @@ -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"
    

  • locale/es.po
    ... ... @@ -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"
    

  • locale/hu.po
    ... ... @@ -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
    

  • src/html/helpdata.cpp
    ... ... @@ -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
     }
    

  • src/msw/checkbox.cpp
    ... ... @@ -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
     // ----------------------------------------------------------------------------
    

  • src/msw/control.cpp
    ... ... @@ -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
     {
    

  • src/msw/radiobut.cpp
    ... ... @@ -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
    

  • src/msw/statbox.cpp
    ... ... @@ -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);
    

  • src/msw/webview_edge.cpp
    ... ... @@ -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)
    

  • src/msw/window.cpp
    ... ... @@ -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
    

  • tests/Makefile.in
    ... ... @@ -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
     
    

  • tests/fuzz/corpus/tar/sample.tar
    No preview for this file type
  • tests/fuzz/ossfuzz.sh
    ... ... @@ -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/*

  • tests/fuzz/tar.cpp
    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
    +}

  • tests/fuzz/tar.options
    1
    +[libfuzzer]
    
    2
    +max_len = 65536

  • tests/html/helpdata.cpp
    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

  • tests/test.bkl
    ... ... @@ -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
    

Reply all
Reply to author
Forward
0 new messages