[Xcb] [PATCH util-keysymy] Fix handling of error connections

Uli Schlachter psychon at znc.in
Sat Nov 16 03:33:40 PST 2013


When an xcb_connection_t goes into an error state, all operations on it will
fail. This means that after a call to xcb_key_symbols_get_reply(), syms->u.reply
would still be a NULL pointer and that xcb_get_setup() returns a NULL pointer.

The only way for xcb_get_setup() to return NULL is for an error connection, but
xcb_get_keyboard_mapping_reply() could also fail for other reasons. So to fix
this, all functions need to check for error connections and if syms->u.reply is
not NULL.

This was tested with the following C code:

  #include <xcb_keysyms.h>
  #include <stdio.h>
  #include <stdlib.h>

  int main()
  {
  	xcb_connection_t *c = xcb_connect(NULL, NULL);
  	xcb_key_symbols_t *syms = xcb_key_symbols_alloc(c);
  	/* The above sent a GetKeyboardMapping request. Let's now break the
  	 * connection so that it cannot get the reply.
  	 */
  	uint32_t max = xcb_get_maximum_request_length(c);
  	xcb_screen_t *s = xcb_setup_roots_iterator(xcb_get_setup(c)).data;
  	size_t len = (max << 2) * 2;
  	void *p = malloc(len);

  	printf("Sending request of length %d*2=%d\n",
  			xcb_get_maximum_request_length(c), len);
  	xcb_change_property(c, XCB_PROP_MODE_REPLACE, s->root,
  			XCB_ATOM_STRING, XCB_ATOM_STRING, 8, len, p);
  	free(p);

  	if (!xcb_connection_has_error(c))
  		puts("Connection did not break :(");

  	/* Crash? */
  	free(xcb_key_symbols_get_keycode(syms, 0xff14));

  	return 0;
  }

Reference: https://awesome.naquadah.org/bugs/index.php?do=details&task_id=1195
Signed-off-by: Uli Schlachter <psychon at znc.in>
---
 keysyms/keysyms.c | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/keysyms/keysyms.c b/keysyms/keysyms.c
index daa863f..419c58b 100644
--- a/keysyms/keysyms.c
+++ b/keysyms/keysyms.c
@@ -77,7 +77,7 @@ xcb_key_symbols_alloc (xcb_connection_t *c)
   xcb_keycode_t     min_keycode;
   xcb_keycode_t     max_keycode;

-  if (!c)
+  if (!c || xcb_connection_has_error(c))
     return NULL;

   syms = malloc (sizeof (xcb_key_symbols_t));
@@ -198,10 +198,13 @@ xcb_keysym_t xcb_key_symbols_get_keysym (xcb_key_symbols_t
*syms,
   xcb_keycode_t max_keycode;
   int        per;

-  if (!syms)
+  if (!syms || xcb_connection_has_error(syms->c))
     return keysym_null;

   xcb_key_symbols_get_reply (syms, NULL);
+
+  if (!syms->u.reply)
+    return keysym_null;

   keysyms = xcb_get_keyboard_mapping_keysyms (syms->u.reply);
   min_keycode = xcb_get_setup (syms->c)->min_keycode;
@@ -245,12 +248,15 @@ xcb_key_symbols_get_keycode(xcb_key_symbols_t *syms,
   int j, nresult = 0;
   xcb_keycode_t i, min, max, *result = NULL, *result_np = NULL;

-  if(syms)
+  if(syms && !xcb_connection_has_error(syms->c))
   {
       xcb_key_symbols_get_reply (syms, NULL);
       min = xcb_get_setup(syms->c)->min_keycode;
       max = xcb_get_setup(syms->c)->max_keycode;

+      if (!syms->u.reply)
+        return NULL;
+
       for(i = min; i && i <= max; i++)
           for(j = 0; j < syms->u.reply->keysyms_per_keycode; j++)
           {
@@ -298,7 +304,7 @@ int
 xcb_refresh_keyboard_mapping (xcb_key_symbols_t         *syms,
 			   xcb_mapping_notify_event_t *event)
 {
-  if (event->request == XCB_MAPPING_KEYBOARD && syms) {
+  if (event->request == XCB_MAPPING_KEYBOARD && syms &&
!xcb_connection_has_error(syms->c)) {
     if (syms->tag == TAG_VALUE) {
       xcb_keycode_t     min_keycode;
       xcb_keycode_t     max_keycode;
-- 
1.8.4.2



More information about the Xcb mailing list