[Xcb] [PATCH libxcb 4/4 V3] generator: fix align-pads for switches which start at unaligned pos

Christian Linhart chris at demorecorder.com
Tue Sep 9 14:26:40 PDT 2014


From: Christian Linhart <chris at DemoRecorder.com>

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
---
 src/c_client.py | 26 +++++++++++++++++++++-----
 1 file changed, 21 insertions(+), 5 deletions(-)

diff --git a/src/c_client.py b/src/c_client.py
index 1d1bbf6..0a1f877 100644
--- a/src/c_client.py
+++ b/src/c_client.py
@@ -653,17 +653,23 @@ def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'):
         for p in param_fields:
             if not p.type.fixed_size():
                 add_param(params, (p.c_field_const_type, '*', p.c_field_name))
 
     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)
 
     if not postpone:
         code_lines.append('%s    if (0 != xcb_pad) {' % space)
 
         if 'serialize' == context:
@@ -673,14 +679,16 @@ def _c_serialize_helper_insert_padding(context, code_lines, space, postpone):
         elif context in ('unserialize', 'unpack', 'sizeof'):
             code_lines.append('%s        xcb_tmp += xcb_pad;' % space)
 
         code_lines.append('%s        xcb_pad = 0;' % space)
         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
 # _c_serialize_helper_insert_padding()
 
 def _c_serialize_helper_switch(context, self, complex_name,
                                code_lines, temp_vars,
@@ -1001,21 +1009,23 @@ def _c_serialize_helper_fields(context, self,
 
         # fields with variable size
         else:
             if field.type.is_pad:
                 # 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,
                                                                          space, prefix)
                 prev_field_was_variable = True
 
         # save (un)serialization C code
@@ -1096,15 +1106,15 @@ def _c_serialize_helper(context, complex_type,
             code_lines.append('%s    xcb_buffer_len += xcb_block_len;' % space)
             code_lines.append('%s    xcb_block_len = 0;' % space)
 
         count += _c_serialize_helper_fields(context, self,
                                             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()
 
 def _c_serialize(context, self):
     """
     depending on the context variable, generate _serialize(), _unserialize(), _unpack(), or _sizeof()
@@ -1166,14 +1176,16 @@ def _c_serialize(context, self):
             _c('    unsigned int xcb_out_pad = -sizeof(%s) & 3;', self.c_type)
             _c('    unsigned int xcb_buffer_len = sizeof(%s) + xcb_out_pad;', self.c_type)
             _c('    unsigned int xcb_align_to = 0;')
         else:
             _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'
 
     elif context in ('unserialize', 'unpack'):
         _c('    char *xcb_tmp = (char *)_buffer;')
         if not self.is_switch:
             if not self.c_var_followed_by_fixed_fields:
@@ -1189,14 +1201,16 @@ def _c_serialize(context, self):
                 aux_var = '(*_aux)' # unserialize: double pointer (!)
             prefix = [(aux_var, '->', self)]
         aux_ptr = '*_aux'
         _c('    unsigned int xcb_buffer_len = 0;')
         _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]
         if self.is_switch:
             # switch: call _unpack()
             _c('    %s _aux;', self.c_type)
             _c('    return %s(%s, &_aux);', self.c_unpack_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
@@ -1206,14 +1220,16 @@ def _c_serialize(context, self):
             # special case: call _unserialize()
             _c('    return %s(%s, NULL);', self.c_unserialize_name, reduce(lambda x,y: "%s, %s" % (x, y), param_names))
             _c('}')
             return
         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'
     variable_size_fields = count
     if 'serialize' == context:
         temp_vars.append('    unsigned int xcb_pad = 0;')
         temp_vars.append('    char xcb_pad0[3] = {0, 0, 0};')
-- 
2.0.1



More information about the Xcb mailing list