Fix out-of-bounds read on trailing % in wxDateTime::Format() Add a unit test but restrict it to only the cases when our own function is used because MSVC CRT strftime() asserts in this case. Closes #26543.
Fix off-by-one in hostent/servent pointer list terminator The h_addr_list/h_aliases/s_aliases copy loops in deepCopyHostent() and deepCopyServent() reserve N pointer slots for N entries and then write the terminator with *++q, one slot too far, so the array isn't terminated right after the last entry and that slot holds copied address/alias bytes used as a pointer. Reserve a slot for the terminator and write it with *q. Closes #26553.
Fix text and column overflow in wxMSW wxListCtrl Compute the items rectangles ourselves as LVM_GETSUBITEMRECT doesn't return the correct result in several cases. Closes #26558.
Capture "this" explicitly in lambda used in wxMSW wxJoystick code Avoid warning about implicit "this" capture being deprecated in C++20.
| ... | ... | @@ -405,8 +405,17 @@ wxString wxDateTime::Format(const wxString& formatp, const TimeZone& tz) const |
| 405 | 405 | continue;
|
| 406 | 406 | }
|
| 407 | 407 | |
| 408 | + // advance to the format specifier following the '%': a trailing '%'
|
|
| 409 | + // is not a valid format, so output it verbatim and stop here instead
|
|
| 410 | + // of letting the loop's own ++p move the iterator past the end
|
|
| 411 | + if ( ++p == format.end() )
|
|
| 412 | + {
|
|
| 413 | + res += wxT('%');
|
|
| 414 | + break;
|
|
| 415 | + }
|
|
| 416 | + |
|
| 408 | 417 | // set the default format
|
| 409 | - switch ( (*++p).GetValue() )
|
|
| 418 | + switch ( (*p).GetValue() )
|
|
| 410 | 419 | {
|
| 411 | 420 | case wxT('Y'): // year has 4 digits
|
| 412 | 421 | case wxT('G'): // (and ISO week year too)
|
| ... | ... | @@ -165,6 +165,7 @@ hostent *deepCopyHostent(hostent *h, |
| 165 | 165 | char **h_addr_list = (char **)(buffer + pos);
|
| 166 | 166 | while(*(p++) != nullptr)
|
| 167 | 167 | pos += sizeof(char *);
|
| 168 | + pos += sizeof(char *); /* and one slot for the null terminator */
|
|
| 168 | 169 | |
| 169 | 170 | /* copy addresses and fill new pointer list */
|
| 170 | 171 | for (p = h->h_addr_list, q = h_addr_list; *p != nullptr; p++, q++)
|
| ... | ... | @@ -178,7 +179,7 @@ hostent *deepCopyHostent(hostent *h, |
| 178 | 179 | *q = buffer + pos; /* set copied pointer to copied content */
|
| 179 | 180 | pos += len;
|
| 180 | 181 | }
|
| 181 | - *++q = nullptr; /* null terminate the pointer list */
|
|
| 182 | + *q = nullptr; /* null terminate the pointer list */
|
|
| 182 | 183 | h->h_addr_list = h_addr_list; /* copy pointer to pointers */
|
| 183 | 184 | |
| 184 | 185 | /* ensure word alignment of pointers */
|
| ... | ... | @@ -191,6 +192,7 @@ hostent *deepCopyHostent(hostent *h, |
| 191 | 192 | char **h_aliases = (char **)(buffer + pos);
|
| 192 | 193 | while(*(p++) != nullptr)
|
| 193 | 194 | pos += sizeof(char *);
|
| 195 | + pos += sizeof(char *); /* and one slot for the null terminator */
|
|
| 194 | 196 | |
| 195 | 197 | /* copy aliases and fill new pointer list */
|
| 196 | 198 | for (p = h->h_aliases, q = h_aliases; *p != nullptr; p++, q++)
|
| ... | ... | @@ -206,7 +208,7 @@ hostent *deepCopyHostent(hostent *h, |
| 206 | 208 | *q = buffer + pos; /* set copied pointer to copied content */
|
| 207 | 209 | pos += len + 1;
|
| 208 | 210 | }
|
| 209 | - *++q = nullptr; /* null terminate the pointer list */
|
|
| 211 | + *q = nullptr; /* null terminate the pointer list */
|
|
| 210 | 212 | h->h_aliases = h_aliases; /* copy pointer to pointers */
|
| 211 | 213 | |
| 212 | 214 | return h;
|
| ... | ... | @@ -310,6 +312,7 @@ servent *deepCopyServent(servent *s, |
| 310 | 312 | char **s_aliases = (char **)(buffer + pos);
|
| 311 | 313 | while(*(p++) != nullptr)
|
| 312 | 314 | pos += sizeof(char *);
|
| 315 | + pos += sizeof(char *); /* and one slot for the null terminator */
|
|
| 313 | 316 | |
| 314 | 317 | /* copy addresses and fill new pointer list */
|
| 315 | 318 | for (p = s->s_aliases, q = s_aliases; *p != nullptr; p++, q++){
|
| ... | ... | @@ -323,7 +326,7 @@ servent *deepCopyServent(servent *s, |
| 323 | 326 | *q = buffer + pos; /* set copied pointer to copied content */
|
| 324 | 327 | pos += len + 1;
|
| 325 | 328 | }
|
| 326 | - *++q = nullptr; /* null terminate the pointer list */
|
|
| 329 | + *q = nullptr; /* null terminate the pointer list */
|
|
| 327 | 330 | s->s_aliases = s_aliases; /* copy pointer to pointers */
|
| 328 | 331 | return s;
|
| 329 | 332 | }
|
| ... | ... | @@ -435,7 +435,7 @@ wxString wxJoystick::GetProductName() const |
| 435 | 435 | if (joyGetDevCaps(m_joystick, &joyCaps, sizeof(joyCaps)) != JOYERR_NOERROR)
|
| 436 | 436 | return wxEmptyString;
|
| 437 | 437 | |
| 438 | - auto GetNameFromReg = [=](wxRegKey::StdKey root) -> wxString
|
|
| 438 | + auto GetNameFromReg = [this, joyCaps](wxRegKey::StdKey root) -> wxString
|
|
| 439 | 439 | {
|
| 440 | 440 | wxString result;
|
| 441 | 441 | wxString subKey1 = wxString::Format(wxT("%s\\%s\\%s"), REGSTR_PATH_JOYCONFIG, joyCaps.szRegKey, REGSTR_KEY_JOYCURR);
|
| ... | ... | @@ -1403,20 +1403,29 @@ bool wxListCtrl::GetSubItemRect(long item, long subItem, wxRect& rect, int code) |
| 1403 | 1403 | |
| 1404 | 1404 | wxCopyRECTToRect(rectWin, rect);
|
| 1405 | 1405 | |
| 1406 | - // We can't use wxGetListCtrlSubItemRect() for the 0th subitem as 0 means
|
|
| 1407 | - // the entire row for this function, so we need to calculate it ourselves.
|
|
| 1408 | - if ( subItem == 0 && code == wxLIST_RECT_BOUNDS )
|
|
| 1406 | + // We can't trust the native LVM_GETSUBITEMRECT for LVIR_BOUNDS because:
|
|
| 1407 | + // - subitem 0 returns the entire row bounds, not just column 0
|
|
| 1408 | + // - when column 0 is narrower than the icon, the native control clamps
|
|
| 1409 | + // all subitems' left edge to at least the icon width, misaligning them
|
|
| 1410 | + //
|
|
| 1411 | + // So for all subitems we calculate x and width from GetColumnWidth() in
|
|
| 1412 | + // visual (column order) order, which always reflects the real column sizes.
|
|
| 1413 | + if ( subItem != wxLIST_GETSUBITEMRECT_WHOLEITEM && code == wxLIST_RECT_BOUNDS )
|
|
| 1409 | 1414 | {
|
| 1410 | - // Because the columns can be reordered, we need to sum the widths of
|
|
| 1411 | - // all preceding columns to get the correct x position.
|
|
| 1415 | + // Start from the row's left edge (which accounts for scrolling).
|
|
| 1416 | + RECT rowRect;
|
|
| 1417 | + wxGetListCtrlItemRect(GetHwnd(), item, LVIR_BOUNDS, rowRect);
|
|
| 1418 | + int x = rowRect.left;
|
|
| 1419 | + |
|
| 1412 | 1420 | for ( auto col : GetColumnsOrder() )
|
| 1413 | 1421 | {
|
| 1414 | 1422 | if ( col == subItem )
|
| 1415 | 1423 | break;
|
| 1416 | 1424 | |
| 1417 | - rect.x += GetColumnWidth(col);
|
|
| 1425 | + x += GetColumnWidth(col);
|
|
| 1418 | 1426 | }
|
| 1419 | 1427 | |
| 1428 | + rect.x = x;
|
|
| 1420 | 1429 | rect.width = GetColumnWidth(subItem);
|
| 1421 | 1430 | }
|
| 1422 | 1431 |
| ... | ... | @@ -800,6 +800,17 @@ TEST_CASE("wxDateTime::Format", "[datetime]") |
| 800 | 800 | |
| 801 | 801 | wxDateTime dt(29, wxDateTime::May, 1976, 18, 30, 15, 678);
|
| 802 | 802 | CHECK( dt.Format("%F %T.%l") == "1976-05-29 18:30:15.678" );
|
| 803 | + |
|
| 804 | + // A format ending in a lone '%' must not read past the end of the format
|
|
| 805 | + // string; the trailing percent is output verbatim. The literal is long
|
|
| 806 | + // enough to be heap-allocated so the over-read trips ASAN without the fix.
|
|
| 807 | + //
|
|
| 808 | + // The MSVC CRT considers a trailing '%' an invalid format string and
|
|
| 809 | + // aborts, so skip this check there. This CRT is also used by MinGW.
|
|
| 810 | +#if !defined(_MSC_VER) && !defined(__MINGW32__)
|
|
| 811 | + CHECK( dt.Format("a long enough format ending in a percent sign %") ==
|
|
| 812 | + "a long enough format ending in a percent sign %" );
|
|
| 813 | +#endif
|
|
| 803 | 814 | }
|
| 804 | 815 | |
| 805 | 816 | TEST_CASE("wxDateTime::ParseFormat", "[datetime]")
|
—
View it on GitLab.
You're receiving this email because of your account on gitlab.com. Manage all notifications · Help