Tab control crash Win10+

Bug #2019492 reported by iceman50
14
This bug affects 2 people
Affects Status Importance Assigned to Milestone
DC++
Fix Released
Medium
Dcplusplus-team

Bug Description

When running DC++ compiled under MSVC (Currently using VS2022) and running on Win10+ DC++ will crash when using OwnerDrawn tabs and selecting button style which will cause DC++ to immediately crash in TabView->handlePainting (You can force this crash on every startup by going into DCPlusPlus.xml and setting the following <TabStyle type="int">6</TabStyle>.

Tags: dwt crash tabview
Revision history for this message
iceman50 (bdcdevel) wrote :
Revision history for this message
RoLex (hundrambit) wrote :

I confirm this when DC++ is compiled under GCC 11.

Revision history for this message
eMTee (realprogger) wrote (last edit ):

The crash happens with x64 builds only and it needs the executable linked with high entropy ASLR <https://learn.microsoft.com/en-us/cpp/build/reference/highentropyva-support-64-bit-aslr?view=msvc-170> enabled. Also it currently crashes only under an operating system that supports this feature such as Win8+.

The cause is that 8 byte-long x64 TabInfo pointers sent through using a <https://learn.microsoft.com/en-us/windows/win32/api/commctrl/ns-commctrl-tcitema> strucure as an item data parameter are getting truncated to 4 bytes when they come out as <https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-drawitemstruct>.itemData or when accessed by TabCtrl_GetItem.

Both TCITEM's and the tab controls's documentation <https://learn.microsoft.com/en-us/windows/win32/controls/tab-controls?redirectedfrom=MSDN#owner-drawn-tabs> mention this. You cannot pass through data with size other than 4 using this method, even though the size of the containter for this data (TCITEM.lParam) is 8 bytes long in x64.

If no high entropy ASLR applied at execution, as the current officially used linker mandates, then the virtual address space allocated for the binary remains under 4GiB hence the pointer truncation has no effect and no crashes happen. But with various linking configurations, operating systems, memory size, etc... this can change at anytime.

A <https://learn.microsoft.com/en-us/windows/win32/api/commctrl/ns-commctrl-tcitemheadera> must be used instead with quirks to work around some undocumented behavior.

A fix, that is under testing right now, will be committed soon.

Changed in dcplusplus:
status: New → Confirmed
importance: Undecided → Medium
Revision history for this message
eMTee (realprogger) wrote :

Seems like the current available Win32 API documentation is inaccurate and / or incomplete regarding how to pass extra data properly using TCM_SETITEMEXTRA message and TCITEMHEADER structure.

First of all (as people also noted in a few other online forums), for TCITEMHEADER the TCIF_PARAM flag in "mask" parameter must be set the same way as in <https://learn.microsoft.com/en-us/windows/win32/api/commctrl/ns-commctrl-tcitema#members> when used for getting or setting a tab item's data. <https://learn.microsoft.com/en-us/windows/win32/api/commctrl/ns-commctrl-tcitemheadera#members> omits this information.

Secondly, unlike the way documented in <https://learn.microsoft.com/en-us/windows/win32/api/commctrl/nf-commctrl-tabctrl_setitemextra> the TabCtrl_SetItemExtra macro indeed has a success/failure return value, it is clear from CommCtrl.h.

And finally, the data size requirement when one wants to pass extra data using TCITEMHEADER is inaccurately documented as well. <https://learn.microsoft.com/en-us/windows/win32/controls/tcm-setitemextra#remarks> says "By default, the number of extra bytes is four." which is valid for 32-bit apps/calls only. In 64-bit apps this default size appears to be 8 bytes since if you set this size by sending a TCM_SETITEMEXTRA message then it is silently discarded and things fall back to the old way when TCITEM is used: you get a 4-byte-long truncated value again when getting tab info and the same wrong _value_ passed through messages containing DRAWITEMSTRUCTs (and not reference to the extra data, as described in <https://learn.microsoft.com/en-us/windows/win32/controls/tab-controls?redirectedfrom=MSDN#owner-drawn-tabs>).

As a workaround, to avoid the extra data size to be either 4 or 8, a dummy byte is added to the extra data structure which makes things work in both architectures.

Changed in dcplusplus:
status: Confirmed → Fix Committed
Revision history for this message
eMTee (realprogger) wrote :

Fixed in DC++ 0.881

Changed in dcplusplus:
status: Fix Committed → Fix Released
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Duplicates of this bug

Other bug subscribers

Bug attachments

Remote bug watches

Bug watches keep track of this bug in other bug trackers.