generator: fix align-pads for switches which start at unaligned pos QueryDeviceState-V5
authorChristian Linhart <chris@DemoRecorder.com>
Tue, 9 Sep 2014 21:26:40 +0000 (23:26 +0200)
committerChristian Linhart <chris@demorecorder.com>
Mon, 20 Oct 2014 10:21:21 +0000 (12:21 +0200)
Fix the alignment computation inside switches which start at
an unaligned pos.
This affects both explicit and implicit align pads.

The alignment offset is derived from the lowest 3 bits of
the pointer to the protocol-data at the start of the switch.
This is sufficient for correcting all alignments up to 8-byte alignment.
As far as I know there is no bigger alignment than 8-byte for the
X-protocol.

Example:
struct InputState, where the switch starts after two 1-byte fields,
which is a 2 byte offset for 4-byte and 8-byte alignment.

The previous problem can be demonstrated when adding a
<pad align="4"/> at the end of case "key".

(Or when finding a testcase which reports the case "valuator" not
at the last position of the QueryDeviceState-reply.
I didn't find such a testcase, so I have used the pad align
as described above.)

V2: patch modified in order to fix bugs which I found when working on the
next issue:
* xcb_padding_offset has to be set 0 when xcb_block_len is set 0
* xcb_padding_offset cannot be "const" therefore
* for unpack and unserialize, the padding_offset must computed
  from _buffer instead of from the aux_var.

V3: patch revised according to suggestion by Ran Benita:
* only create and use xcb_padding_offset for switch

Message-ID: <1410298000-24734-1-git-send-email-chris@demorecorder.com>
Patch-Thread-Subject: [Xcb] xinput:QueryDeviceState: full-support: generator and xml-changes
Patch-Set: QueryDeviceState
Patch-Number: libxcb 4/4
Patch-Version: V3
Signed-off-by: Christian Linhart <chris@DemoRecorder.com>
Reviewed-By: Ran Benita <ran234@gmail.com>
src/c_client.py

index 1d1bbf6..0a1f877 100644 (file)
@@ -657,9 +657,15 @@ def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'):
     return (param_fields, wire_fields, params)
 # get_serialize_params()
 
-def _c_serialize_helper_insert_padding(context, code_lines, space, postpone):
+def _c_serialize_helper_insert_padding(context, code_lines, space, postpone, is_case_or_bitcase):
     code_lines.append('%s    /* insert padding */' % space)
-    code_lines.append('%s    xcb_pad = -xcb_block_len & (xcb_align_to - 1);' % space)
+    if is_case_or_bitcase:
+        code_lines.append(
+            '%s    xcb_pad = -(xcb_block_len + xcb_padding_offset) & (xcb_align_to - 1);'
+            % space)
+    else:
+        code_lines.append(
+            '%s    xcb_pad = -xcb_block_len & (xcb_align_to - 1);' % space)
 #    code_lines.append('%s    printf("automatically inserting padding: %%%%d\\n", xcb_pad);' % space)
     code_lines.append('%s    xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
 
@@ -677,6 +683,8 @@ def _c_serialize_helper_insert_padding(context, code_lines, space, postpone):
         code_lines.append('%s    }' % space)
 
     code_lines.append('%s    xcb_block_len = 0;' % space)
+    if is_case_or_bitcase:
+        code_lines.append('%s    xcb_padding_offset = 0;' % space)
 
     # keep tracking of xcb_parts entries for serialize
     return 1
@@ -1005,13 +1013,15 @@ def _c_serialize_helper_fields(context, self,
                 # Variable length pad is <pad align= />
                 code_lines.append('%s    xcb_align_to = %d;' % (space, field.type.align))
                 count += _c_serialize_helper_insert_padding(context, code_lines, space,
-                                                        self.c_var_followed_by_fixed_fields)
+                                                            self.c_var_followed_by_fixed_fields,
+                                                            is_case_or_bitcase)
                 continue
             else:
                 # switch/bitcase: always calculate padding before and after variable sized fields
                 if need_padding or is_case_or_bitcase:
                     count += _c_serialize_helper_insert_padding(context, code_lines, space,
-                                                            self.c_var_followed_by_fixed_fields)
+                                                                self.c_var_followed_by_fixed_fields,
+                                                                is_case_or_bitcase)
 
                 value, length = _c_serialize_helper_fields_variable_size(context, self, field,
                                                                          code_lines, temp_vars,
@@ -1100,7 +1110,7 @@ def _c_serialize_helper(context, complex_type,
                                             code_lines, temp_vars,
                                             space, prefix, False)
     # "final padding"
-    count += _c_serialize_helper_insert_padding(context, code_lines, space, False)
+    count += _c_serialize_helper_insert_padding(context, code_lines, space, False, self.is_switch)
 
     return count
 # _c_serialize_helper()
@@ -1170,6 +1180,8 @@ def _c_serialize(context, self):
             _c('    char *xcb_out = *_buffer;')
             _c('    unsigned int xcb_buffer_len = 0;')
             _c('    unsigned int xcb_align_to = 0;')
+        if self.is_switch:
+            _c('    unsigned int xcb_padding_offset = ((size_t)xcb_out) & 7;')
         prefix = [('_aux', '->', self)]
         aux_ptr = 'xcb_out'
 
@@ -1193,6 +1205,8 @@ def _c_serialize(context, self):
         _c('    unsigned int xcb_block_len = 0;')
         _c('    unsigned int xcb_pad = 0;')
         _c('    unsigned int xcb_align_to = 0;')
+        if self.is_switch:
+            _c('    unsigned int xcb_padding_offset = ((size_t)_buffer) & 7;')
 
     elif 'sizeof' == context:
         param_names = [p[2] for p in params]
@@ -1210,6 +1224,8 @@ def _c_serialize(context, self):
         else:
             _c('    char *xcb_tmp = (char *)_buffer;')
             prefix = [('_aux', '->', self)]
+            if self.is_switch:
+                _c('    unsigned int xcb_padding_offset = 0;')
 
     count = _c_serialize_helper(context, self, code_lines, temp_vars, prefix=prefix)
     # update variable size fields (only important for context=='serialize'