diff --git a/tests/display-test.c b/tests/display-test.c index a8e11f1d..cf571fac 100644 --- a/tests/display-test.c +++ b/tests/display-test.c @@ -1422,3 +1422,68 @@ TEST(registry_bind_interface_mismatch) display_destroy(d); } + +static void +send_overflow_client(void *data) +{ + struct client *c = client_connect(); + int i, err = 0; + int *pipes = data; + char tmp = '\0'; + + /* On Linux, the Unix socket default buffer size is <=256KB, and + * each noop request requires 8 bytes; the buffer should thus + * overflow within about 32K /unhandled/ iterations */ + for (i = 0; i < 1000000; i++) { + noop_request(c); + err = wl_display_get_error(c->wl_display); + if (err) + break; + } + + /* Do not close the pipe file descriptors afterwards, because the leak + * check verifies that the initial/final FD counts are the same */ + assert(write(pipes[1], &tmp, sizeof(tmp)) == (ssize_t)sizeof(tmp)); + + /* Expect an error */ + fprintf(stderr, "Send loop failed on try %d, err = %d, %s\n", i, err, strerror(err)); + assert(err == EAGAIN); + + client_disconnect_nocheck(c); +} + +TEST(send_overflow_disconnection) +{ + struct display *d; + struct client_info *c; + char tmp; + int rpipe[2]; + int i; + + assert(pipe(rpipe) != -1); + + d = display_create(); + + c = client_create(d, send_overflow_client, &rpipe); + + /* Close write end of the pipe, so that the later read() call gets + * interrupted if the client dies */ + close(rpipe[1]); + + /* At least 2 loops of this are needed to respond for the client to + * set up the test interface */ + for (i = 0; i < 5; i++) { + wl_display_flush_clients(d->wl_display); + wl_event_loop_dispatch(wl_display_get_event_loop(d->wl_display), -1); + } + + /* Wait until all noop requests have been sent, or until client + * process aborts */ + (void)read(rpipe[0], &tmp, sizeof(tmp)); + close(rpipe[0]); + + /* For a clean shutdown */ + display_run(d); + + display_destroy(d); +} diff --git a/tests/test-compositor.c b/tests/test-compositor.c index 72f63515..bd2b0156 100644 --- a/tests/test-compositor.c +++ b/tests/test-compositor.c @@ -45,7 +45,8 @@ struct test_compositor; static const struct wl_message tc_requests[] = { /* this request serves as a barrier for synchronizing*/ - { "stop_display", "u", NULL } + { "stop_display", "u", NULL }, + { "noop", "", NULL }, }; static const struct wl_message tc_events[] = { @@ -54,7 +55,7 @@ static const struct wl_message tc_events[] = { const struct wl_interface test_compositor_interface = { "test", 1, - 1, tc_requests, + 2, tc_requests, 1, tc_events }; @@ -62,6 +63,8 @@ struct test_compositor_interface { void (*stop_display)(struct wl_client *client, struct wl_resource *resource, uint32_t num); + void (*noop)(struct wl_client *client, + struct wl_resource *resource); }; struct test_compositor_listener { @@ -70,7 +73,8 @@ struct test_compositor_listener { }; enum { - STOP_DISPLAY = 0 + STOP_DISPLAY = 0, + TEST_NOOP = 1 }; enum { @@ -294,8 +298,16 @@ handle_stop_display(struct wl_client *client, wl_display_terminate(d->wl_display); } +static void +handle_noop(struct wl_client *client, struct wl_resource *resource) +{ + (void)client; + (void)resource; +} + static const struct test_compositor_interface tc_implementation = { - handle_stop_display + handle_stop_display, + handle_noop, }; static void @@ -509,3 +521,9 @@ stop_display(struct client *c, int num) return n; } + +void +noop_request(struct client *c) +{ + wl_proxy_marshal((struct wl_proxy *) c->tc, TEST_NOOP); +} diff --git a/tests/test-compositor.h b/tests/test-compositor.h index 876d0c09..90999b2f 100644 --- a/tests/test-compositor.h +++ b/tests/test-compositor.h @@ -70,6 +70,7 @@ struct client { struct client *client_connect(void); void client_disconnect(struct client *); int stop_display(struct client *, int); +void noop_request(struct client *); /** * Usual workflow: