diff options
author | Uli Schlachter <psychon@znc.in> | 2013-11-16 12:33:40 +0100 |
---|---|---|
committer | Uli Schlachter <psychon@znc.in> | 2014-02-22 17:24:15 +0100 |
commit | ae88512d7f142a50a75a48ff52320e5e1f3ad236 (patch) | |
tree | 6194775e00e9729940f5983d3a6517264c84ec66 | |
parent | 3d7b2ba8299cb2d0e2f5e58f61c1a60625f2d015 (diff) | |
download | util-keysyms-ae88512d7f142a50a75a48ff52320e5e1f3ad236.tar.gz |
Fix handling of error connections
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@znc.in>
-rw-r--r-- | keysyms/keysyms.c | 14 |
1 files 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; |