[Git][wxwidgets/wxwidgets][master] 5 commits: Fix wxURI::IsReference() description

1 view
Skip to first unread message

Vadim Zeitlin (@_VZ_)

unread,
May 30, 2026, 11:56:03 AM (8 days ago) May 30
to wx-commi...@googlegroups.com

Vadim Zeitlin pushed to branch master at wxWidgets / wxWidgets

Commits:

  • 41969e24
    by ryancog at 2026-05-30T16:57:22+02:00
    Fix wxURI::IsReference() description
    
    The documentation described the inverse of the name of the
    function and what it actually did, fix it to describe the actual
    function behaviour.
    
    Closes #26520.
    
  • 83d55d0a
    by dxbjavid at 2026-05-30T17:00:44+02:00
    Fix one-byte over-read in IFF decomprle replicate packet
    
    The replicate-run branch reads the packet's data byte after only
    checking that one source byte remains, but it consumes two (the control
    byte plus the data byte). A BODY ending in a lone replicate control byte
    then reads one byte past the input buffer. Require two bytes left,
    matching the literal-run check above.
    
    Closes #26518.
    
  • 2647c080
    by dxbjavid at 2026-05-30T17:04:10+02:00
    Fix buffer overflow when loading invalid message catalogs
    
    Avoid integer overflow in message catalog StringAtOfs() bounds check:
    StringAtOfs() read ofsString and nLen from the .mo file and checked
    ofsString + nLen against the data length, but both are 32-bit so the
    sum wraps and a translated entry declaring nLen 0xffffffff passes the
    check; FillHash() then scans past the end of the catalog. Compute the
    offset as a 64-bit value so the addition can't overflow and result in an
    invalid index into the buffer.
    
    Add a test feeding such a catalog through wxMsgCatalog::CreateFromData().
    
    Closes #26513.
    
  • 46f928d0
    by dxbjavid at 2026-05-30T17:12:17+02:00
    Fix buffer overflow on invalid width in wxXPMDecoder
    
    Fix integer overflow in wxXPMDecoder::ReadData() when computing
    width*chars_per_pixel: a header with a (very) large width could result
    in wrapping around and result in reasonable but yet invalid value, which
    could let the key-reading loop run off the end of the buffer.
    
    Compute the product in 64-bits to avoid the overflow.
    
    Closes #26519.
    
  • 262cec29
    by dxbjavid at 2026-05-30T17:34:07+02:00
    Fix data-size bound check past LIST chunk in wxSound::LoadWAV()
    
    The check compared ul against length minus the fixed offset FMT_INDEX +
    uiSize + 16, which equals data_offset + 8 only when no LIST chunk is
    present. When a LIST chunk is present data_offset has already been
    advanced past it, so a crafted WAV can pass this check with ul larger
    than the bytes that actually follow the data-chunk header, and the
    OSS/SDL playback paths then read past m_dataWithHeader. Use data_offset
    directly so the same constraint holds either way.
    
    Closes #26525.
    

7 changed files:

Changes:

  • interface/wx/uri.h
    ... ... @@ -259,8 +259,8 @@ public:
    259 259
         bool IsEmpty() const;
    
    260 260
     
    
    261 261
         /**
    
    262
    -        Returns @true if a valid [absolute] URI, otherwise this URI is a URI
    
    263
    -        reference and not a full URI, and this function returns @false.
    
    262
    +        Returns @false if a valid [absolute] URI, otherwise this URI is a URI
    
    263
    +        reference and not a full URI, and this function returns @true.
    
    264 264
         */
    
    265 265
         bool IsReference() const;
    
    266 266
     
    

  • src/common/imagiff.cpp
    ... ... @@ -276,7 +276,7 @@ static void decomprle(const byte *sptr, byte *dptr, long slen, long dlen)
    276 276
     
    
    277 277
         else if (codeByte > 0x80) {
    
    278 278
             codeByte = 0x81 - (codeByte & 0x7f);
    
    279
    -        if ((slen > (long) 0) && (dlen >= (long) codeByte)) {
    
    279
    +        if ((slen > (long) 1) && (dlen >= (long) codeByte)) {
    
    280 280
             dataByte = *sptr++;
    
    281 281
             slen -= 2;
    
    282 282
             dlen -= codeByte;
    

  • src/common/translation.cpp
    ... ... @@ -873,7 +873,7 @@ private:
    873 873
             const wxMsgTableEntry * const ent = pTable + n;
    
    874 874
     
    
    875 875
             // this check could fail for a corrupt message catalog
    
    876
    -        size_t32 ofsString = Swap(ent->ofsString);
    
    876
    +        wxULongLong_t ofsString = Swap(ent->ofsString);
    
    877 877
             if ( ofsString + Swap(ent->nLen) > m_data.length())
    
    878 878
             {
    
    879 879
                 return nullptr;
    

  • src/common/xpmdecod.cpp
    ... ... @@ -787,7 +787,8 @@ wxImage wxXPMDecoder::ReadData(const char* const* xpm_data)
    787 787
             for (i = 0; i < width; i++, img_data += 3)
    
    788 788
             {
    
    789 789
                 const char *xpmImgLine = xpm_data[1 + colors_cnt + j];
    
    790
    -            if ( !xpmImgLine || strlen(xpmImgLine) < width*chars_per_pixel )
    
    790
    +            if ( !xpmImgLine ||
    
    791
    +                    strlen(xpmImgLine) < (unsigned long long)width*chars_per_pixel )
    
    791 792
                 {
    
    792 793
                     wxLogError(_("XPM: truncated image data at line %d!"),
    
    793 794
                                (int)(1 + colors_cnt + j));
    

  • src/unix/sound.cpp
    ... ... @@ -714,8 +714,10 @@ bool wxSound::LoadWAV(const void* data_, size_t length, bool copyData)
    714 714
         memcpy(&ul, &data[data_offset + 4u], 4);
    
    715 715
         ul = wxUINT32_SWAP_ON_BE(ul);
    
    716 716
     
    
    717
    -    // ensure we actually have at least that much data in the input
    
    718
    -    if (ul > length - FMT_INDEX - waveformat.uiSize - 16)
    
    717
    +    // ensure we actually have at least that much data in the input; use
    
    718
    +    // data_offset rather than the fixed FMT_INDEX + uiSize + 16 expression
    
    719
    +    // so that an optional LIST chunk is accounted for here as well.
    
    720
    +    if (ul > length - data_offset - 8u)
    
    719 721
             return false;
    
    720 722
     
    
    721 723
         m_data = new wxSoundData;
    

  • tests/image/image.cpp
    ... ... @@ -1542,6 +1542,27 @@ TEST_CASE_METHOD(ImageHandlersInit, "wxImage::BadXPMUnterminatedQuote",
    1542 1542
         REQUIRE( !img.LoadFile(mis, wxBITMAP_TYPE_XPM) );
    
    1543 1543
     }
    
    1544 1544
     
    
    1545
    +TEST_CASE_METHOD(ImageHandlersInit, "wxImage::BadXPMWidthOverflow",
    
    1546
    +                 "[image][xpm][error]")
    
    1547
    +{
    
    1548
    +    // width * chars_per_pixel was computed in 32-bit unsigned in
    
    1549
    +    // wxXPMDecoder::ReadData() and used to check that each image line is long
    
    1550
    +    // enough, but the per-pixel index uses size_t arithmetic. With width =
    
    1551
    +    // 68174085 and chars_per_pixel = 63 the product is 4 294 967 355, which
    
    1552
    +    // wraps to 59, so a one-pixel image line passes the length check and the
    
    1553
    +    // key-reading loop then runs off the end of the buffer. Loading such a
    
    1554
    +    // file must be rejected.
    
    1555
    +    const std::string key(63, 'a');
    
    1556
    +    const std::string xpm =
    
    1557
    +        "/* XPM */\n"
    
    1558
    +        "\"68174085 1 1 63\"\n"
    
    1559
    +        "\"" + key + " c #ffffff\"\n"
    
    1560
    +        "\"" + key + "\"\n";
    
    1561
    +    wxMemoryInputStream mis(xpm.data(), xpm.size());
    
    1562
    +    wxImage img;
    
    1563
    +    REQUIRE( !img.LoadFile(mis, wxBITMAP_TYPE_XPM) );
    
    1564
    +}
    
    1565
    +
    
    1545 1566
     #endif // wxUSE_XPM
    
    1546 1567
     
    
    1547 1568
     #if wxUSE_IFF
    
    ... ... @@ -1649,6 +1670,43 @@ TEST_CASE_METHOD(ImageHandlersInit, "wxImage::BadIFFBodyTruncated",
    1649 1670
         REQUIRE( !img.LoadFile(mis, wxBITMAP_TYPE_IFF) );
    
    1650 1671
     }
    
    1651 1672
     
    
    1673
    +TEST_CASE_METHOD(ImageHandlersInit, "wxImage::BadIFFRLEBody",
    
    1674
    +                 "[image][iff][error]")
    
    1675
    +{
    
    1676
    +    // A run-length encoded (compression == 1) BODY whose data is a single
    
    1677
    +    // replicate control byte (0xFF) with no following data byte. decomprle()
    
    1678
    +    // only checked that one source byte remained before reading the replicate
    
    1679
    +    // packet's data byte, so it read bodyptr[1], one byte past the end of the
    
    1680
    +    // heap-allocated input buffer. transparentColor = 0x4000 makes
    
    1681
    +    // ConvertToImage() reject the result so the load fails with the fix.
    
    1682
    +    wxImage::AddHandler(new wxIFFHandler);
    
    1683
    +
    
    1684
    +    static const unsigned char data[] =
    
    1685
    +    {
    
    1686
    +        0x46,0x4f,0x52,0x4d,            // "FORM"
    
    1687
    +        0x00,0x00,0x00,0x29,            // FORM length (not validated)
    
    1688
    +        0x49,0x4c,0x42,0x4d,            // "ILBM"
    
    1689
    +        0x42,0x4d,0x48,0x44,            // "BMHD"
    
    1690
    +        0x00,0x00,0x00,0x14,            // BMHD chunk length = 20
    
    1691
    +        0x00,0x08,                      // width  = 8
    
    1692
    +        0x00,0x01,                      // height = 1
    
    1693
    +        0x00,0x00,0x00,0x00,            // x, y
    
    1694
    +        0x01,                           // nPlanes
    
    1695
    +        0x00,                           // masking
    
    1696
    +        0x01,                           // compression = 1 (RLE)
    
    1697
    +        0x00,                           // pad
    
    1698
    +        0x40,0x00,                      // transparentColor = 0x4000
    
    1699
    +        0x00,0x00,                      // x/y aspect
    
    1700
    +        0x00,0x00,0x00,0x00,            // page width / height
    
    1701
    +        0x42,0x4f,0x44,0x59,            // "BODY"
    
    1702
    +        0x00,0x00,0x00,0x64,            // BODY chunk length = 100 (lie)
    
    1703
    +        0xff,                           // lone replicate control byte
    
    1704
    +    };
    
    1705
    +    wxMemoryInputStream mis(data, WXSIZEOF(data));
    
    1706
    +    wxImage img;
    
    1707
    +    REQUIRE( !img.LoadFile(mis, wxBITMAP_TYPE_IFF) );
    
    1708
    +}
    
    1709
    +
    
    1652 1710
     #endif // wxUSE_IFF
    
    1653 1711
     
    
    1654 1712
     TEST_CASE_METHOD(ImageHandlersInit, "wxImage::DibPadding", "[image]")
    

  • tests/intl/intltest.cpp
    ... ... @@ -18,6 +18,7 @@
    18 18
     #endif // WX_PRECOMP
    
    19 19
     
    
    20 20
     #include "wx/intl.h"
    
    21
    +#include "wx/translation.h"
    
    21 22
     #include "wx/uilocale.h"
    
    22 23
     #include "wx/scopeguard.h"
    
    23 24
     
    
    ... ... @@ -291,6 +292,46 @@ TEST_CASE("wxTranslations::AddCatalog", "[translations]")
    291 292
         }
    
    292 293
     }
    
    293 294
     
    
    295
    +TEST_CASE("wxTranslations::CorruptCatalog", "[translations]")
    
    296
    +{
    
    297
    +    // Build a minimal MO catalog with two strings whose second translated
    
    298
    +    // entry declares a length of 0xffffffff. Adding this to the (valid) string
    
    299
    +    // offset wraps around in 32-bit arithmetic and used to defeat the bounds
    
    300
    +    // check in StringAtOfs(), letting FillHash() read past the end of the data.
    
    301
    +    //
    
    302
    +    // The catalog is 64 bytes; the backing array has one extra byte because
    
    303
    +    // wxCharTypeBuffer copies len+1 bytes (it assumes a trailing NUL).
    
    304
    +    const size_t moLen = 64;
    
    305
    +    unsigned char mo[moLen + 1];
    
    306
    +    memset(mo, 0, sizeof(mo));
    
    307
    +
    
    308
    +    auto put32 = [](unsigned char* p, wxUint32 v)
    
    309
    +    {
    
    310
    +        p[0] = (unsigned char)(v & 0xff);
    
    311
    +        p[1] = (unsigned char)((v >> 8) & 0xff);
    
    312
    +        p[2] = (unsigned char)((v >> 16) & 0xff);
    
    313
    +        p[3] = (unsigned char)((v >> 24) & 0xff);
    
    314
    +    };
    
    315
    +
    
    316
    +    put32(mo +  0, 0x950412de); // magic
    
    317
    +    put32(mo +  8, 2);          // number of strings
    
    318
    +    put32(mo + 12, 28);         // offset of original strings table
    
    319
    +    put32(mo + 16, 44);         // offset of translated strings table
    
    320
    +    // original strings table
    
    321
    +    put32(mo + 28, 0);  put32(mo + 32, 60); // ""
    
    322
    +    put32(mo + 36, 1);  put32(mo + 40, 61); // "x"
    
    323
    +    // translated strings table
    
    324
    +    put32(mo + 44, 0);          put32(mo + 48, 60); // ""
    
    325
    +    put32(mo + 52, 0xffffffff); put32(mo + 56, 63); // bogus length
    
    326
    +    mo[61] = 'x';
    
    327
    +    mo[63] = 'A'; // unterminated string at the very end of the buffer
    
    328
    +
    
    329
    +    wxCharTypeBuffer<char> data(reinterpret_cast<const char*>(mo), moLen);
    
    330
    +    wxMsgCatalog* const cat = wxMsgCatalog::CreateFromData(data, "corrupt");
    
    331
    +    CHECK( cat == nullptr );
    
    332
    +    delete cat;
    
    333
    +}
    
    334
    +
    
    294 335
     TEST_CASE("wxTranslations::GetBestTranslation", "[translations]")
    
    295 336
     {
    
    296 337
         wxFileTranslationsLoader::AddCatalogLookupPathPrefix("./intl");
    

Reply all
Reply to author
Forward
0 new messages