Remove wxPathOnly(wxChar*) overload This overload was not declared nor exported from (shared) libraries, so just remove it.
Reimplement wxPathOnly() using wxFileName::GetPath() Add tests checking that the function still performs as before and document that its behaviour slightly differs from GetPath().
Validate decoded pixel indices in wxGIFDecoder::ConvertToImage() Avoid reading uninitialized memory if any of the pixels in the input data reference entries beyond the end of the palette. Closes #26521.
Avoid writing beyond the buffer end for GIFs with zero size Reject GIF frames with zero width or height to avoid writing beyond the (empty) buffer returned by malloc(0). Closes #26524.
Fix buffer overflow in wxVsnprintf() when size==0 Don't write NUL byte to "buf[size - 1]" when size is 0. This bug was present in both implementations of wxVsnprintf(), so fix it in both places too. Closes #26522.
Fix palette buffer overflow in wxGIFHandler::SaveFile() The image palette can have more than the 256 entries a GIF supports, for example when the image was loaded from an XPM that declares a larger colour count. wxGIFHandler_GetPalette(), called when saving a GIF, copied every entry into the caller's fixed wxRGB pal[256] buffer, overflowing it. Such an image can't be represented as a GIF, so reject the save with an error message instead of overflowing the buffer or writing out a silently truncated palette. Closes #26532.
Merge branch 'reimplement-pathonly' Reimplement wxPathOnly() using wxFileName::GetPath(). This incidentally fixes a buffer overflow in this function, see #26526. See #26537.
| ... | ... | @@ -294,6 +294,19 @@ wxString wxGetWorkingDirectory(char* buf = nullptr, int sz = 1000); |
| 294 | 294 | /**
|
| 295 | 295 | Returns the directory part of the filename.
|
| 296 | 296 | |
| 297 | + @deprecated Please use wxFileName::GetPath() instead.
|
|
| 298 | + |
|
| 299 | + Note that the behaviour of this function is slightly different for Windows
|
|
| 300 | + paths including drive letters: it returns a string without trailing
|
|
| 301 | + backslash for the absolute paths with drive letters and a string with
|
|
| 302 | + trailing dot for the relative paths with drive letters.
|
|
| 303 | + |
|
| 304 | + Since wxWidgets 3.3.3 all path separators are normalized to the current
|
|
| 305 | + platform path separator in the returned path, i.e. under Windows forward
|
|
| 306 | + slashes in @a path will be replaced with backslashes in the returned value.
|
|
| 307 | + Previous versions of wxWidgets didn't perform this normalization and
|
|
| 308 | + returned the path with the same separators as in @a path.
|
|
| 309 | + |
|
| 297 | 310 | @header{wx/filefn.h}
|
| 298 | 311 | */
|
| 299 | 312 | wxString wxPathOnly(const wxString& path);
|
| ... | ... | @@ -261,105 +261,34 @@ wxString wxFileNameFromPath (const wxString& path) |
| 261 | 261 | return wxFileName(path).GetFullName();
|
| 262 | 262 | }
|
| 263 | 263 | |
| 264 | -// Return just the directory, or nullptr if no directory
|
|
| 265 | -wxChar *
|
|
| 266 | -wxPathOnly (wxChar *path)
|
|
| 267 | -{
|
|
| 268 | - if (path && *path)
|
|
| 269 | - {
|
|
| 270 | - static wxChar buf[_MAXPATHLEN];
|
|
| 271 | - |
|
| 272 | - int l = wxStrlen(path);
|
|
| 273 | - int i = l - 1;
|
|
| 274 | - if ( i >= _MAXPATHLEN )
|
|
| 275 | - return nullptr;
|
|
| 276 | - |
|
| 277 | - // Local copy
|
|
| 278 | - wxStrcpy (buf, path);
|
|
| 279 | - |
|
| 280 | - // Search backward for a backward or forward slash
|
|
| 281 | - while (i > -1)
|
|
| 282 | - {
|
|
| 283 | - // Unix like or Windows
|
|
| 284 | - if (path[i] == wxT('/') || path[i] == wxT('\\'))
|
|
| 285 | - {
|
|
| 286 | - buf[i] = 0;
|
|
| 287 | - return buf;
|
|
| 288 | - }
|
|
| 289 | -#ifdef __VMS__
|
|
| 290 | - if (path[i] == wxT(']'))
|
|
| 291 | - {
|
|
| 292 | - buf[i+1] = 0;
|
|
| 293 | - return buf;
|
|
| 294 | - }
|
|
| 295 | -#endif
|
|
| 296 | - i --;
|
|
| 297 | - }
|
|
| 298 | - |
|
| 299 | -#if defined(__WINDOWS__)
|
|
| 300 | - // Try Drive specifier
|
|
| 301 | - if (wxIsalpha (buf[0]) && buf[1] == wxT(':'))
|
|
| 302 | - {
|
|
| 303 | - // A:junk --> A:. (since A:.\junk Not A:\junk)
|
|
| 304 | - buf[2] = wxT('.');
|
|
| 305 | - buf[3] = wxT('\0');
|
|
| 306 | - return buf;
|
|
| 307 | - }
|
|
| 308 | -#endif
|
|
| 309 | - }
|
|
| 310 | - return nullptr;
|
|
| 311 | -}
|
|
| 312 | - |
|
| 313 | -// Return just the directory, or nullptr if no directory
|
|
| 264 | +// Return just the directory, or empty string if no directory
|
|
| 314 | 265 | wxString wxPathOnly (const wxString& path)
|
| 315 | 266 | {
|
| 316 | - if (!path.empty())
|
|
| 317 | - {
|
|
| 318 | - wxChar buf[_MAXPATHLEN];
|
|
| 319 | - |
|
| 320 | - int l = path.length();
|
|
| 321 | - int i = l - 1;
|
|
| 322 | - |
|
| 323 | - if ( i >= _MAXPATHLEN )
|
|
| 324 | - return wxString();
|
|
| 325 | - |
|
| 326 | - // Local copy
|
|
| 327 | - wxStrcpy(buf, path);
|
|
| 328 | - |
|
| 329 | - // Search backward for a backward or forward slash
|
|
| 330 | - while (i > -1)
|
|
| 331 | - {
|
|
| 332 | - // Unix like or Windows
|
|
| 333 | - if (path[i] == wxT('/') || path[i] == wxT('\\'))
|
|
| 334 | - {
|
|
| 335 | - // Don't return an empty string
|
|
| 336 | - if (i == 0)
|
|
| 337 | - i ++;
|
|
| 338 | - buf[i] = 0;
|
|
| 339 | - return wxString(buf);
|
|
| 340 | - }
|
|
| 341 | -#ifdef __VMS__
|
|
| 342 | - if (path[i] == wxT(']'))
|
|
| 343 | - {
|
|
| 344 | - buf[i+1] = 0;
|
|
| 345 | - return wxString(buf);
|
|
| 346 | - }
|
|
| 347 | -#endif
|
|
| 348 | - i --;
|
|
| 349 | - }
|
|
| 267 | + wxString res = wxFileName(path).GetPath();
|
|
| 350 | 268 | |
| 269 | + // For compatibility with the old behaviour of this function, we need to
|
|
| 270 | + // return "X:" for paths with volume and absolute path under Windows and
|
|
| 271 | + // "X:." for paths with volume and relative path.
|
|
| 351 | 272 | #if defined(__WINDOWS__)
|
| 352 | - // Try Drive specifier
|
|
| 353 | - if (wxIsalpha (buf[0]) && buf[1] == wxT(':'))
|
|
| 273 | + if ( res.size() >= 2 && wxIsalpha(res[0]) && res[1] == wxT(':') )
|
|
| 274 | + {
|
|
| 275 | + switch ( res.size() )
|
|
| 354 | 276 | {
|
| 355 | - // A:junk --> A:. (since A:.\junk Not A:\junk)
|
|
| 356 | - buf[2] = wxT('.');
|
|
| 357 | - buf[3] = wxT('\0');
|
|
| 358 | - return wxString(buf);
|
|
| 277 | + case 2:
|
|
| 278 | + // "X:" --> "X:."
|
|
| 279 | + res += wxT('.');
|
|
| 280 | + break;
|
|
| 281 | + |
|
| 282 | + case 3:
|
|
| 283 | + // "X:\" --> "X:"
|
|
| 284 | + if ( res[2] == wxFILE_SEP_PATH )
|
|
| 285 | + res.erase(2);
|
|
| 286 | + break;
|
|
| 359 | 287 | }
|
| 360 | -#endif
|
|
| 361 | 288 | }
|
| 362 | - return wxEmptyString;
|
|
| 289 | +#endif // __WINDOWS__
|
|
| 290 | + |
|
| 291 | + return res;
|
|
| 363 | 292 | }
|
| 364 | 293 | |
| 365 | 294 | // Utility for converting delimiters in DOS filenames to UNIX style
|
| ... | ... | @@ -151,6 +151,25 @@ bool wxGIFDecoder::ConvertToImage(unsigned int frame, wxImage *image) const |
| 151 | 151 | dst = image->GetData();
|
| 152 | 152 | transparent = GetTransparentColourIndex(frame);
|
| 153 | 153 | |
| 154 | + // Reject decoded pixels that reference palette entries past the
|
|
| 155 | + // loaded portion of the per-frame palette buffer: GIF files where
|
|
| 156 | + // the LZW minimum code size implies a larger alphabet than the
|
|
| 157 | + // declared colour table can emit literal codes >= ncolours. pimg->pal
|
|
| 158 | + // is a fixed 768 bytes but only 3*ncolours of them are populated from
|
|
| 159 | + // the file (the rest is left uninitialised), so the pal[3*(*src) + ...]
|
|
| 160 | + // reads below would otherwise pull uninitialised bytes into the image.
|
|
| 161 | + // The index stays within the 768-byte buffer (a pixel byte is at most
|
|
| 162 | + // 255), so this is an uninitialised read rather than an out-of-bounds
|
|
| 163 | + // one, but it still leaks junk into the decoded pixels.
|
|
| 164 | + unsigned long npixel =
|
|
| 165 | + static_cast<unsigned long>(sz.GetWidth()) * sz.GetHeight();
|
|
| 166 | + const unsigned int ncolours = GetNcolours(frame);
|
|
| 167 | + for (i = 0; i < npixel; i++)
|
|
| 168 | + {
|
|
| 169 | + if (src[i] >= ncolours)
|
|
| 170 | + return false;
|
|
| 171 | + }
|
|
| 172 | + |
|
| 154 | 173 | // set transparent colour mask
|
| 155 | 174 | if (transparent != -1)
|
| 156 | 175 | {
|
| ... | ... | @@ -223,7 +242,6 @@ bool wxGIFDecoder::ConvertToImage(unsigned int frame, wxImage *image) const |
| 223 | 242 | #endif // wxUSE_PALETTE
|
| 224 | 243 | |
| 225 | 244 | // copy image data
|
| 226 | - unsigned long npixel = sz.GetWidth() * sz.GetHeight();
|
|
| 227 | 245 | for (i = 0; i < npixel; i++, src++)
|
| 228 | 246 | {
|
| 229 | 247 | *(dst++) = pal[3 * (*src) + 0];
|
| ... | ... | @@ -839,6 +857,14 @@ wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) |
| 839 | 857 | interl = ((buf[8] & 0x40)? 1 : 0);
|
| 840 | 858 | size = pimg->w * pimg->h;
|
| 841 | 859 | |
| 860 | + // Reject frames with zero width or height: malloc(0) below
|
|
| 861 | + // returns an empty allocation that the dgif() decode loop
|
|
| 862 | + // still writes into. The subsequent-frames check above
|
|
| 863 | + // rejects zero size in animations but the first frame and
|
|
| 864 | + // the non-animated GIF87a path both reach here unchecked.
|
|
| 865 | + if (size == 0)
|
|
| 866 | + return wxGIF_INVFORMAT;
|
|
| 867 | + |
|
| 842 | 868 | pimg->transparent = transparent;
|
| 843 | 869 | pimg->disposal = disposal;
|
| 844 | 870 | pimg->delay = delay;
|
| ... | ... | @@ -556,6 +556,16 @@ bool wxGIFHandler_GetPalette(const wxImage& image, |
| 556 | 556 | const wxPalette& palette = image.GetPalette();
|
| 557 | 557 | int palCount = palette.GetColoursCount();
|
| 558 | 558 | |
| 559 | + // The caller's pal[] buffer only has room for the 256 entries a GIF can
|
|
| 560 | + // hold. A wxImage palette may be larger, e.g. when the image was loaded
|
|
| 561 | + // from an XPM declaring more than 256 colours, and such an image can't be
|
|
| 562 | + // represented as a GIF, so fail the save here rather than overflow pal[].
|
|
| 563 | + if (palCount > 256)
|
|
| 564 | + {
|
|
| 565 | + wxLogError(_("Image palette has too many colours to save as GIF."));
|
|
| 566 | + return false;
|
|
| 567 | + }
|
|
| 568 | + |
|
| 559 | 569 | for (int i = 0; i < palCount; ++i)
|
| 560 | 570 | {
|
| 561 | 571 | if (!palette.GetRGB(i, &pal[i].red, &pal[i].green, &pal[i].blue))
|
| ... | ... | @@ -516,7 +516,7 @@ int ConvertStringToBuf(const wxString& s, char *out, size_t outsize) |
| 516 | 516 | {
|
| 517 | 517 | memcpy(out, buf, len+1);
|
| 518 | 518 | }
|
| 519 | - else // not enough space
|
|
| 519 | + else if ( outsize > 0 ) // not enough space
|
|
| 520 | 520 | {
|
| 521 | 521 | memcpy(out, buf, outsize-1);
|
| 522 | 522 | out[outsize-1] = '\0';
|
| ... | ... | @@ -535,7 +535,7 @@ int ConvertStringToBuf(const wxString& s, wchar_t *out, size_t outsize) |
| 535 | 535 | {
|
| 536 | 536 | memcpy(out, buf, (len+1) * sizeof(wchar_t));
|
| 537 | 537 | }
|
| 538 | - else // not enough space
|
|
| 538 | + else if ( outsize > 0 ) // not enough space
|
|
| 539 | 539 | {
|
| 540 | 540 | memcpy(out, buf, (outsize-1) * sizeof(wchar_t));
|
| 541 | 541 | out[outsize-1] = 0;
|
| ... | ... | @@ -605,7 +605,8 @@ int wxVsnprintf(char *str, size_t size, const wxString& format, va_list argptr) |
| 605 | 605 | |
| 606 | 606 | // VsnprintfTestCase reveals that glibc's implementation of vswprintf
|
| 607 | 607 | // doesn't nul terminate on truncation.
|
| 608 | - str[size - 1] = 0;
|
|
| 608 | + if ( size )
|
|
| 609 | + str[size - 1] = 0;
|
|
| 609 | 610 | |
| 610 | 611 | return rv;
|
| 611 | 612 | }
|
| ... | ... | @@ -94,6 +94,12 @@ static int wxDoVsnprintf(CharType *buf, size_t lenMax, |
| 94 | 94 | wprintf(L"Using wxCRT_VsnprintfW\n");
|
| 95 | 95 | #endif
|
| 96 | 96 | |
| 97 | + // If the output buffer is of size 0 we can't write anything to it, not
|
|
| 98 | + // even the terminating NUL, so just bail out: continuing would underflow
|
|
| 99 | + // lenCur below and access buf[(size_t)-1], writing out of bounds.
|
|
| 100 | + if ( lenMax == 0 )
|
|
| 101 | + return -1;
|
|
| 102 | + |
|
| 97 | 103 | wxPrintfConvSpecParser<CharType> parser(format);
|
| 98 | 104 | |
| 99 | 105 | wxPrintfArg argdata[wxMAX_SVNPRINTF_ARGUMENTS];
|
| ... | ... | @@ -488,6 +488,17 @@ TEST_CASE_METHOD(FileFunctionsTestCase, |
| 488 | 488 | wxString pathOnly = wxPathOnly(filename.GetFullPath());
|
| 489 | 489 | if ( !wxDirExists(pathOnly) )
|
| 490 | 490 | CHECK( pathOnly == wxString() );
|
| 491 | + |
|
| 492 | + CHECK( wxPathOnly(wxString{}) == "" );
|
|
| 493 | + CHECK( wxPathOnly("foo") == "" );
|
|
| 494 | + CHECK( wxPathOnly("foo/") == "foo" );
|
|
| 495 | + CHECK( wxPathOnly("/foo/") == wxString(wxFILE_SEP_PATH) + "foo" );
|
|
| 496 | + |
|
| 497 | +#ifdef __WINDOWS__
|
|
| 498 | + CHECK( wxPathOnly("c:\\foo.exe") == "c:" );
|
|
| 499 | + CHECK( wxPathOnly("c:foo.exe") == "c:." );
|
|
| 500 | + CHECK( wxPathOnly("foo\\bar.dll") == "foo" );
|
|
| 501 | +#endif
|
|
| 491 | 502 | }
|
| 492 | 503 | |
| 493 | 504 | // Unit tests for Mkdir and Rmdir doesn't cover non-ASCII directory names.
|
| ... | ... | @@ -1304,6 +1304,30 @@ TEST_CASE_METHOD(ImageHandlersInit, "wxImage::SaveAnimatedGIF", "[image]") |
| 1304 | 1304 | #endif // #if wxUSE_PALETTE
|
| 1305 | 1305 | }
|
| 1306 | 1306 | |
| 1307 | +TEST_CASE_METHOD(ImageHandlersInit, "wxImage::SaveGIFBigPalette", "[image][gif][error]")
|
|
| 1308 | +{
|
|
| 1309 | +#if wxUSE_PALETTE
|
|
| 1310 | + // An image palette can have more than the 256 entries a GIF supports, for
|
|
| 1311 | + // instance when the image was loaded from an XPM declaring a larger colour
|
|
| 1312 | + // count. Saving such an image as GIF must not overflow the fixed 256-entry
|
|
| 1313 | + // palette buffer used by the encoder; instead the save should fail cleanly.
|
|
| 1314 | + const int numColours = 300;
|
|
| 1315 | + unsigned char r[numColours], g[numColours], b[numColours];
|
|
| 1316 | + for (int i = 0; i < numColours; ++i)
|
|
| 1317 | + {
|
|
| 1318 | + r[i] = g[i] = b[i] = static_cast<unsigned char>(i);
|
|
| 1319 | + }
|
|
| 1320 | + |
|
| 1321 | + wxImage image(1, 1);
|
|
| 1322 | + image.SetRGB(0, 0, 0, 0, 0);
|
|
| 1323 | + image.SetPalette(wxPalette(numColours, r, g, b));
|
|
| 1324 | + |
|
| 1325 | + wxMemoryOutputStream memOut;
|
|
| 1326 | + wxLogNull noLog;
|
|
| 1327 | + CHECK( !image.SaveFile(memOut, wxBITMAP_TYPE_GIF) );
|
|
| 1328 | +#endif // wxUSE_PALETTE
|
|
| 1329 | +}
|
|
| 1330 | + |
|
| 1307 | 1331 | static void TestGIFComment(const wxString& comment)
|
| 1308 | 1332 | {
|
| 1309 | 1333 | wxImage image("horse.gif");
|
| ... | ... | @@ -1414,6 +1438,65 @@ TEST_CASE_METHOD(ImageHandlersInit, "wxImage::BadGIFLZWMinCodeSize", |
| 1414 | 1438 | REQUIRE( !img.LoadFile(mis, wxBITMAP_TYPE_GIF) );
|
| 1415 | 1439 | }
|
| 1416 | 1440 | |
| 1441 | +TEST_CASE_METHOD(ImageHandlersInit, "wxImage::BadGIFPaletteIndex",
|
|
| 1442 | + "[image][gif][error]")
|
|
| 1443 | +{
|
|
| 1444 | + // A 1x1 GIF whose LSDB declares a 2-entry global colour table but whose
|
|
| 1445 | + // LZW minimum code size is 3, giving an 8-literal alphabet. The frame's
|
|
| 1446 | + // LZW data emits CLEAR, literal 2, EOI -- pixel value 2 is a valid LZW
|
|
| 1447 | + // literal but past the end of the 2-entry palette, so the
|
|
| 1448 | + // pal[3*(*src) + ...] reads in wxGIFDecoder::ConvertToImage() previously
|
|
| 1449 | + // pulled uninitialised bytes from the unpopulated tail of the 768-byte
|
|
| 1450 | + // pimg->pal buffer into the decoded image. The index stays inside the
|
|
| 1451 | + // buffer (a pixel byte is at most 255) so ASAN won't flag it, but it is
|
|
| 1452 | + // an uninitialised read that MSAN catches and leaks junk into the pixels.
|
|
| 1453 | + static const unsigned char data[] =
|
|
| 1454 | + {
|
|
| 1455 | + 0x47, 0x49, 0x46, 0x38, 0x39, 0x61, // "GIF89a"
|
|
| 1456 | + 0x01, 0x00, 0x01, 0x00, 0x80, 0x00, 0x00, // LSDB: 1x1, GCT, 2col
|
|
| 1457 | + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, // GCT entries
|
|
| 1458 | + 0x2c, // image separator
|
|
| 1459 | + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, // 1x1 frame at 0,0
|
|
| 1460 | + 0x00, // no LCT
|
|
| 1461 | + 0x03, // LZW min code size=3
|
|
| 1462 | + 0x02, 0x28, 0x09, // sub-block: CLEAR,2,EOI
|
|
| 1463 | + 0x00, // sub-block terminator
|
|
| 1464 | + 0x3b, // trailer
|
|
| 1465 | + };
|
|
| 1466 | + wxMemoryInputStream mis(data, WXSIZEOF(data));
|
|
| 1467 | + wxImage img;
|
|
| 1468 | + REQUIRE( !img.LoadFile(mis, wxBITMAP_TYPE_GIF) );
|
|
| 1469 | +}
|
|
| 1470 | + |
|
| 1471 | +TEST_CASE_METHOD(ImageHandlersInit, "wxImage::BadGIFZeroFrameSize",
|
|
| 1472 | + "[image][gif][error]")
|
|
| 1473 | +{
|
|
| 1474 | + // Per-frame width/height are read from the image descriptor without
|
|
| 1475 | + // checking for zero. When either dimension is zero, pimg->w * pimg->h
|
|
| 1476 | + // is 0 and the subsequent malloc(0) leaves an empty buffer that dgif()
|
|
| 1477 | + // still writes into as soon as the LZW stream emits a literal code,
|
|
| 1478 | + // overflowing the heap allocation. The existing zero-size check only
|
|
| 1479 | + // covers the second and later frames of an animation; the first frame
|
|
| 1480 | + // of an animation, and any GIF87a frame, both reach the allocation
|
|
| 1481 | + // unchecked.
|
|
| 1482 | + static const unsigned char data[] =
|
|
| 1483 | + {
|
|
| 1484 | + 0x47, 0x49, 0x46, 0x38, 0x37, 0x61, // "GIF87a"
|
|
| 1485 | + 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, // LSDB: 1x1, no GCT
|
|
| 1486 | + 0x2c, // image separator
|
|
| 1487 | + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, // frame at 0,0, w=1 h=0
|
|
| 1488 | + 0x80, // LCT, depth=0 (2 col)
|
|
| 1489 | + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, // LCT entries
|
|
| 1490 | + 0x02, // LZW min code size=2
|
|
| 1491 | + 0x02, 0x44, 0x01, // sub-block: CLR/lit/EOI
|
|
| 1492 | + 0x00, // sub-block terminator
|
|
| 1493 | + 0x3b, // trailer
|
|
| 1494 | + };
|
|
| 1495 | + wxMemoryInputStream mis(data, WXSIZEOF(data));
|
|
| 1496 | + wxImage img;
|
|
| 1497 | + REQUIRE( !img.LoadFile(mis, wxBITMAP_TYPE_GIF) );
|
|
| 1498 | +}
|
|
| 1499 | + |
|
| 1417 | 1500 | #endif // wxUSE_GIF
|
| 1418 | 1501 | |
| 1419 | 1502 | #if wxUSE_PCX
|
| ... | ... | @@ -278,3 +278,25 @@ TEST_CASE("CRT::Strtox", "[crt][strtod][strtol]") |
| 278 | 278 | #endif
|
| 279 | 279 | }
|
| 280 | 280 | }
|
| 281 | + |
|
| 282 | +TEST_CASE("CRT::SnprintfZeroSize", "[crt][snprintf]")
|
|
| 283 | +{
|
|
| 284 | + // wxVsnprintf() used to unconditionally execute str[size - 1] = 0 on
|
|
| 285 | + // return; with size == 0 this wraps to str[SIZE_MAX] and corrupts memory
|
|
| 286 | + // (or crashes). The same off-by-one was present in the underlying
|
|
| 287 | + // ConvertStringToBuf() helper which performed memcpy of (outsize-1) bytes
|
|
| 288 | + // when outsize was 0. Check that both narrow and wide overloads of
|
|
| 289 | + // wxSnprintf() leave the supplied buffer untouched when size is 0.
|
|
| 290 | + char bufa[8] = { 'a','b','c','d','e','f','g','h' };
|
|
| 291 | + wchar_t bufw[8] = { L'a',L'b',L'c',L'd',L'e',L'f',L'g',L'h' };
|
|
| 292 | + |
|
| 293 | + (void)wxSnprintf(bufa, 0, "test");
|
|
| 294 | + (void)wxSnprintf(bufw, 0, L"test");
|
|
| 295 | + |
|
| 296 | + for ( size_t i = 0; i < 8; i++ )
|
|
| 297 | + {
|
|
| 298 | + INFO("i=" << i);
|
|
| 299 | + CHECK( bufa[i] == "abcdefgh"[i] );
|
|
| 300 | + CHECK( bufw[i] == L"abcdefgh"[i] );
|
|
| 301 | + }
|
|
| 302 | +} |
—
View it on GitLab.
You're receiving this email because of your account on gitlab.com. Manage all notifications · Help