diff options
author | Uli Schlachter <psychon@znc.in> | 2013-12-31 15:05:36 +0100 |
---|---|---|
committer | Uli Schlachter <psychon@znc.in> | 2014-03-21 14:38:58 +0100 |
commit | 4dcbfd77b78ca6b016ce815af26235501f6cd75a (patch) | |
tree | 3c848875f27c3f98df05b31b2e6cc27d3996e1b2 | |
parent | d84dd752ef571491b015443fefedca53c7f81282 (diff) |
xcb_disconnect(): Fix leak with error connections
There are two kind of error connections in XCB. First, if something goes wrong
while the connection is being set up, _xcb_conn_ret_error() is used to return a
static connection in an error state. If something goes wrong later,
_xcb_conn_shutdown() is used to set c->has_error.
This is important, because the static object that _xcb_conn_ret_error() returns
must not be freed, while the dynamically allocated objects that go through
_xcb_conn_shutdown() must obviously be properly deallocated.
This used to work correctly, but in 769acff0da8, xcb_disconnect() was made to
ignore all connections in an error state completely. Fix this by only ignoring
the few static error connections that we have.
This was tested with the following hack:
xcb_connection_t *c = xcb_connect(NULL, NULL);
close(xcb_get_file_descriptor(c));
xcb_discard_reply(c, xcb_get_input_focus(c).sequence);
xcb_flush(c);
xcb_disconnect(c);
Valgrind confirms that xcb has a memory leak before this patch that this patch
indeed fixes.
Signed-off-by: Uli Schlachter <psychon@znc.in>
Reviewed-by: Julien Cristau <jcristau@debian.org>
-rw-r--r-- | src/xcb_conn.c | 11 |
1 files changed, 10 insertions, 1 deletions
diff --git a/src/xcb_conn.c b/src/xcb_conn.c index ae51b93..ab901a9 100644 --- a/src/xcb_conn.c +++ b/src/xcb_conn.c @@ -64,11 +64,20 @@ typedef struct { uint16_t length; } xcb_setup_generic_t; +/* Keep this list in sync with is_static_error_conn()! */ static const int xcb_con_error = XCB_CONN_ERROR; static const int xcb_con_closed_mem_er = XCB_CONN_CLOSED_MEM_INSUFFICIENT; static const int xcb_con_closed_parse_er = XCB_CONN_CLOSED_PARSE_ERR; static const int xcb_con_closed_screen_er = XCB_CONN_CLOSED_INVALID_SCREEN; +static int is_static_error_conn(xcb_connection_t *c) +{ + return c == (xcb_connection_t *) &xcb_con_error || + c == (xcb_connection_t *) &xcb_con_closed_mem_er || + c == (xcb_connection_t *) &xcb_con_closed_parse_er || + c == (xcb_connection_t *) &xcb_con_closed_screen_er; +} + static int set_fd_flags(const int fd) { /* Win32 doesn't have file descriptors and the fcntl function. This block sets the socket in non-blocking mode */ @@ -341,7 +350,7 @@ xcb_connection_t *xcb_connect_to_fd(int fd, xcb_auth_info_t *auth_info) void xcb_disconnect(xcb_connection_t *c) { - if(c->has_error) + if(is_static_error_conn(c)) return; free(c->setup); |