| Summary: | xinput2 XIQueryDevice reply not read correctly | ||
|---|---|---|---|
| Product: | XCB | Reporter: | Ran Benita <ran234> |
| Component: | Protocol | Assignee: | xcb mailing list dummy <xcb> |
| Status: | RESOLVED FIXED | QA Contact: | xcb mailing list dummy <xcb> |
| Severity: | normal | ||
| Priority: | medium | ||
| Version: | unspecified | ||
| Hardware: | Other | ||
| OS: | All | ||
| Whiteboard: | |||
| i915 platform: | i915 features: | ||
| Bug Depends on: | |||
| Bug Blocks: | 71752 | ||
| Attachments: |
XIQueryDevice test
reset xcb_block_len xcb_get_setup test reset xcb_block_len (with commit message) reset xcb_block_len (with commit message) |
||
After discussing this with Daniel Martin on irc, the problem in this specific instance is the following snippet in the generated xinput.c:
int
xcb_input_xi_device_info_sizeof (const void *_buffer /**< */)
{
char *xcb_tmp = (char *)_buffer;
[...]
unsigned int xcb_block_len = 0;
[...]
xcb_block_len += sizeof(xcb_input_xi_device_info_t);
xcb_tmp += xcb_block_len;
/* name */
xcb_block_len += (((_aux->name_len + 3) / 4) * 4) * sizeof(char);
xcb_tmp += xcb_block_len;
[...]
}
There's a missing
xcb_block_len = 0;
above the /* name */ comment, which results in xcb_tmp being incremented by sizeof(xcb_input_xi_device_info_t) twice, which is of course one too many.
This function xcb_input_xi_device_info_sizeof() is used by xcb_input_xi_device_info_next(), which is used in the test program, which therefore doesn't work.
Daniel says the problemtic section in c_client.py is this:
http://cgit.freedesktop.org/xcb/libxcb/tree/src/c_client.py?id=0289348f2c4ed3b1b286c51df19d82c6787c2b36#n1015
But that simply adding a 'xcb_block_len = 0;' there breaks other iterators.
The same issue also affects other requests, like XKB's GetGeometry.
Created attachment 84415 [details] [review] reset xcb_block_len Thanks for the patch Daniel. So it seems this bug is pretty far-reaching; basically all of the _sizeof() functions have it, though it only manifests on the ones which actually use xcb_tmp for anything. So to see the affected functions, you can grep for the pattern "(xcb_tmp)". Most of them are _sizeof()'s of requests/events/errors, which no one cares about I think. But some are used in iterators for _next() functions. The most affected extensions are xkb and xinput, but also others. For example, I'm pretty sure xcb_get_setup() is broken when there is more than one Screen (roots_len > 1) - in this case the attached program should show garbage. So, if you submit the patch with some commit message, Tested-By: Ran Benita <ran234@gmail.com> Reviewed-By: Ran Benita <ran234@gmail.com> As the fix seems pretty obvious, fixes this test and doesn't cause any other problems that I've seen. And I also think this is ample demonstration that no one is using the _sizeof() functions directly, and that they should therefore be static in the c files and not exposed in the headers; I also think this will reduce the extension library sizes substantially due to dead code elimination. Created attachment 84441 [details]
xcb_get_setup test
(In reply to comment #3) > For example, > I'm pretty sure xcb_get_setup() is broken when there is more than one Screen > (roots_len > 1) - in this case the attached program should show garbage. Nope, works fine here. I tested this against "Xephyr -screen 1000x500 -screen 500x500 :1" and diff't the output for the two screens. Only IDs were different (e.g. the visual IDs). What exactly would you expect to go wrong and why does it still work correctly? (In reply to comment #5) > (In reply to comment #3) > > For example, > > I'm pretty sure xcb_get_setup() is broken when there is more than one Screen > > (roots_len > 1) - in this case the attached program should show garbage. > > Nope, works fine here. I tested this against "Xephyr -screen 1000x500 > -screen 500x500 :1" and diff't the output for the two screens. Only IDs were > different (e.g. the visual IDs). > > What exactly would you expect to go wrong and why does it still work > correctly? Thanks for trying, I didn't know about this Xephyr trick. And you're right; while xcb_screen_sizeof() uses xcb_tmp, it doesn't in fact increment it twice: xcb_block_len += sizeof(xcb_screen_t); xcb_tmp += xcb_block_len; /* allowed_depths */ for(i=0; i<_aux->allowed_depths_len; i++) { xcb_tmp_len = xcb_depth_sizeof(xcb_tmp); xcb_block_len += xcb_tmp_len; xcb_tmp += xcb_tmp_len; } i.e in this case the struct and the depths are considered in the same 'block' (intended or not...). By looking, there aren't any iterator bugs in xproto to show off :) like in xinput and xkb. However to 'compensate', xcb_setup_sizeof() is definitely broken, e.g. on my machine, should be: 5972, reported: 6284. To see this you can add printf("offset: %ld\n", (char *) visuals_iter.data - (char *) setup); right after xcb_visualtype_next(&visuals_iter); and look at the last offset. With the patch the reported sizeof is correct. Created attachment 89413 [details] [review] reset xcb_block_len (with commit message) Attached Daniel's patch with a commit message (adapted from the bug). The diff on the generated code shows some 364 locations where the two lines are added, all of them _sizeof() functions. Most _sizeof() are not used neither internally for iterators nor externally (I've never seen them used anywhere), so could have been broken silently for years. Out of the ones used for iterators, I believe there are two situations: - The changes have no semantic change, as in the screens example (see above comment); it just splits a big "block" to two, having the same end result. - It fixes a real bug rendering the iterators usable, like in xinput2 and xkb (the previously attached test crashes without, works with). The diff is too large for me to inspect every change manually, but I did look at some random sample. I also tried the patched libxcb with some qt5 applications, and there weren't any problems. So I think the patch should go in. Created attachment 89518 [details] [review] reset xcb_block_len (with commit message) Thanks Ran for sanitizing the patch. In this updated version I've added myself as reviewer and removed the preceeding 2 lines: # probably not needed #_c_serialize_helper_insert_padding(context, code_lines, space, False) The _c_serialize_helper_insert_padding() had been commented out with: 22e1013 added accessors for special cases and thereby partly caused that regression. Partly because, the implicit padding would set xcb_block_len to zero as we want, but the implicit padding itself might lead to other length/offset calculation problems. After filtering out _sizeof()s for events, requests and replies the list of affected locations shrinks to 50. These are the structs for the remaining _sizeof()s:
Input - AddMaster
Input - ButtonClass
Input - DeviceClass
Input - DeviceCtl
Input - DeviceName
Input - DeviceResolutionCtl
Input - DeviceResolutionState
Input - DeviceState
Input - EventMask
Input - FeedbackCtl
Input - FeedbackState
Input - HierarchyChange
Input - InputState
Input - KeyClass
Input - StringFeedbackCtl
Input - StringFeedbackState
Input - ValuatorInfo
Input - ValuatorState
Input - XIDeviceInfo
RandR - RefreshRates
Record - ClientInfo
Render - PICTDEPTH
Render - PICTSCREEN
Res - ClientIdValue
Res - ResourceSizeValue
SELinux - ListItem
Sync - SYSTEMCOUNTER
Xv - AdaptorInfo
Xv - AttributeInfo
Xv - EncodingInfo
Xv - Image
xkb - CountedString16
xkb - DeviceLedInfo
xkb - KeySymMap
xkb - KeyType
xkb - Listing
xkb - Outline
xkb - Overlay
xkb - OverlayRow
xkb - Row
xkb - SetKeyType
xkb - Shape
xproto - DEPTH
xproto - HOST
xproto - SCREEN
xproto - STR
xproto - Setup
xproto - SetupAuthenticate
xproto - SetupFailed
xproto - SetupRequest
I've thought about filtering even more, i.e. only the structs that are used in a list. But, the effort didn't seemed worth it.
So, if you find a list using such a struct and try to iterate over it, then it's very likely that you hit this bug too.
(In reply to comment #8) > Created attachment 89518 [details] [review] [review] > reset xcb_block_len (with commit message) With this patch applied the bug can be closed (from my pov). Merged as commit 18f0afab3f0de68114fe185e89d8b25a8c072a2c |
Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.
Created attachment 84398 [details] XIQueryDevice test Trying to use the XIQueryDevice from the recently-merged xinput2 support, the reply seems to be read incorrectly starting from the second XIDeviceInfo. The test code I've used is attached (you can comment the assert's to get a bit further, then it will probably segfault).