xref: /aosp_15_r20/external/wayland/tests/display-test.c (revision 84e872a0dc482bffdb63672969dd03a827d67c73)
1 /*
2  * Copyright © 2012 Intel Corporation
3  * Copyright © 2013 Jason Ekstrand
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the
14  * next paragraph) shall be included in all copies or substantial
15  * portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24  * SOFTWARE.
25  */
26 
27 #define _GNU_SOURCE
28 #include <stdbool.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdarg.h>
32 #include <stdint.h>
33 #include <string.h>
34 #include <assert.h>
35 #include <sys/socket.h>
36 #include <unistd.h>
37 #include <errno.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <sys/mman.h>
41 
42 #include <pthread.h>
43 #include <poll.h>
44 
45 #include "wayland-private.h"
46 #include "wayland-server.h"
47 #include "wayland-client.h"
48 #include "test-runner.h"
49 #include "test-compositor.h"
50 
51 #include "tests-server-protocol.h"
52 #include "tests-client-protocol.h"
53 
54 struct display_destroy_listener {
55 	struct wl_listener listener;
56 	int done;
57 };
58 
59 static void
display_destroy_notify(struct wl_listener * l,void * data)60 display_destroy_notify(struct wl_listener *l, void *data)
61 {
62 	struct display_destroy_listener *listener;
63 
64 	listener = wl_container_of(l, listener, listener);
65 	listener->done = 1;
66 }
67 
TEST(display_destroy_listener)68 TEST(display_destroy_listener)
69 {
70 	struct wl_display *display;
71 	struct display_destroy_listener a, b;
72 
73 	display = wl_display_create();
74 	assert(display);
75 
76 	a.listener.notify = &display_destroy_notify;
77 	a.done = 0;
78 	wl_display_add_destroy_listener(display, &a.listener);
79 
80 	assert(wl_display_get_destroy_listener(display, display_destroy_notify) ==
81 	       &a.listener);
82 
83 	b.listener.notify = display_destroy_notify;
84 	b.done = 0;
85 	wl_display_add_destroy_listener(display, &b.listener);
86 
87 	wl_list_remove(&a.listener.link);
88 
89 	wl_display_destroy(display);
90 
91 	assert(!a.done);
92 	assert(b.done);
93 }
94 
95 /* Fake 'client' which does not use wl_display_connect, and thus leaves the
96  * file descriptor passed through WAYLAND_SOCKET intact. This should not
97  * trigger an assertion in the leak check. */
98 static void
empty_client(void)99 empty_client(void)
100 {
101 	return;
102 }
103 
TEST(tc_leaks_tests)104 TEST(tc_leaks_tests)
105 {
106 	struct display *d = display_create();
107 	client_create_noarg(d, empty_client);
108 	display_run(d);
109 	display_destroy(d);
110 }
111 
112 /* This is how pre proxy-version registry binds worked,
113  * this should create a proxy that shares the display's
114  * version number: 0 */
115 static void *
old_registry_bind(struct wl_registry * wl_registry,uint32_t name,const struct wl_interface * interface,uint32_t version)116 old_registry_bind(struct wl_registry *wl_registry,
117 		  uint32_t name,
118 		  const struct wl_interface *interface,
119 		  uint32_t version)
120 {
121 	struct wl_proxy *id;
122 
123 	id = wl_proxy_marshal_constructor(
124 		(struct wl_proxy *) wl_registry, WL_REGISTRY_BIND,
125 		interface, name, interface->name, version, NULL);
126 
127 	return (void *) id;
128 }
129 
130 struct handler_info {
131 	struct wl_seat *seat;
132 	uint32_t bind_version;
133 	bool use_unversioned;
134 };
135 
136 static void
registry_handle_globals(void * data,struct wl_registry * registry,uint32_t id,const char * intf,uint32_t ver)137 registry_handle_globals(void *data, struct wl_registry *registry,
138 			uint32_t id, const char *intf, uint32_t ver)
139 {
140 	struct handler_info *hi = data;
141 
142 	/* This is only for the proxy version test */
143 	if (hi->bind_version)
144 		ver = hi->bind_version;
145 
146 	if (strcmp(intf, "wl_seat") == 0) {
147 		if (hi->use_unversioned)
148 			hi->seat = old_registry_bind(registry, id,
149 						     &wl_seat_interface, ver);
150 		else
151 			hi->seat = wl_registry_bind(registry, id,
152 						    &wl_seat_interface, ver);
153 		assert(hi->seat);
154 	}
155 }
156 
157 static const struct wl_registry_listener registry_listener = {
158 	registry_handle_globals,
159 	NULL
160 };
161 
162 static struct wl_seat *
client_get_seat_with_info(struct client * c,struct handler_info * hi)163 client_get_seat_with_info(struct client *c, struct handler_info *hi)
164 {
165 	struct wl_registry *reg = wl_display_get_registry(c->wl_display);
166 	assert(reg);
167 
168 	assert(hi);
169 	hi->seat = NULL;
170 	wl_registry_add_listener(reg, &registry_listener, hi);
171 	wl_display_roundtrip(c->wl_display);
172 	assert(hi->seat);
173 
174 	wl_registry_destroy(reg);
175 
176 	return hi->seat;
177 }
178 
179 static struct wl_seat *
client_get_seat(struct client * c)180 client_get_seat(struct client *c)
181 {
182 	struct handler_info hi;
183 
184 	hi.use_unversioned = false;
185 	hi.bind_version = 0;
186 
187 	return client_get_seat_with_info(c, &hi);
188 }
189 
190 static void
check_pending_error(struct client * c,struct wl_proxy * proxy)191 check_pending_error(struct client *c, struct wl_proxy *proxy)
192 {
193 	uint32_t ec, id;
194 	int err;
195 	const struct wl_interface *intf;
196 
197 	err = wl_display_get_error(c->wl_display);
198 	assert(err == EPROTO);
199 
200 	ec = wl_display_get_protocol_error(c->wl_display, &intf, &id);
201 	assert(ec == 23);
202 	assert(intf == &wl_seat_interface);
203 	assert(id == wl_proxy_get_id(proxy));
204 }
205 
206 static void
check_for_error(struct client * c,struct wl_proxy * proxy)207 check_for_error(struct client *c, struct wl_proxy *proxy)
208 {
209 	/* client should be disconnected */
210 	assert(wl_display_roundtrip(c->wl_display) == -1);
211 
212 	check_pending_error(c, proxy);
213 }
214 
215 static struct client_info *
find_client_info(struct display * d,struct wl_client * client)216 find_client_info(struct display *d, struct wl_client *client)
217 {
218 	struct client_info *ci;
219 
220 	wl_list_for_each(ci, &d->clients, link) {
221 		if (ci->wl_client == client)
222 			return ci;
223 	}
224 
225 	return NULL;
226 }
227 
228 static void
bind_seat(struct wl_client * client,void * data,uint32_t vers,uint32_t id)229 bind_seat(struct wl_client *client, void *data,
230 	  uint32_t vers, uint32_t id)
231 {
232 	struct display *d = data;
233 	struct client_info *ci;
234 	struct wl_resource *res;
235 
236 	ci = find_client_info(d, client);
237 	assert(ci);
238 
239 	res = wl_resource_create(client, &wl_seat_interface, vers, id);
240 	assert(res);
241 
242 	/* save the resource as client's info data,
243 	 * so that we can use it later */
244 	ci->data = res;
245 }
246 
247 static void
client_disconnect_nocheck(struct client * c)248 client_disconnect_nocheck(struct client *c)
249 {
250 	wl_proxy_destroy((struct wl_proxy *) c->tc);
251 	wl_display_disconnect(c->wl_display);
252 	free(c);
253 }
254 
255 static void
post_error_main(void)256 post_error_main(void)
257 {
258 	struct client *c = client_connect();
259 	struct wl_seat *seat = client_get_seat(c);
260 
261 	/* stop display so that it can post the error.
262 	 * The function should return -1, because of the posted error */
263 	assert(stop_display(c, 1) == -1);
264 
265 	/* display should have posted error, check it! */
266 	check_for_error(c, (struct wl_proxy *) seat);
267 
268 	/* don't call client_disconnect(c), because then the test would be
269 	 * aborted due to checks for error in this function */
270 	wl_proxy_destroy((struct wl_proxy *) seat);
271 	client_disconnect_nocheck(c);
272 }
273 
TEST(post_error_to_one_client)274 TEST(post_error_to_one_client)
275 {
276 	struct display *d = display_create();
277 	struct client_info *cl;
278 
279 	wl_global_create(d->wl_display, &wl_seat_interface,
280 			 1, d, bind_seat);
281 
282 	cl = client_create_noarg(d, post_error_main);
283 	display_run(d);
284 
285 	/* the display was stopped by client, so it can
286 	 * proceed in the code and post an error */
287 	assert(cl->data);
288 	wl_resource_post_error((struct wl_resource *) cl->data,
289 			       23, "Dummy error");
290 
291 	/* this one should be ignored */
292 	wl_resource_post_error((struct wl_resource *) cl->data,
293 			       21, "Dummy error (ignore)");
294 
295 	display_resume(d);
296 	display_destroy(d);
297 }
298 
299 static void
post_error_main2(void)300 post_error_main2(void)
301 {
302 	struct client *c = client_connect();
303 	struct wl_seat *seat = client_get_seat(c);
304 
305 	/* the error should not be posted for this client */
306 	assert(stop_display(c, 2) >= 0);
307 
308 	wl_proxy_destroy((struct wl_proxy *) seat);
309 	client_disconnect(c);
310 }
311 
312 static void
post_error_main3(void)313 post_error_main3(void)
314 {
315 	struct client *c = client_connect();
316 	struct wl_seat *seat = client_get_seat(c);
317 
318 	assert(stop_display(c, 2) == -1);
319 	check_for_error(c, (struct wl_proxy *) seat);
320 
321 	/* don't call client_disconnect(c), because then the test would be
322 	 * aborted due to checks for error in this function */
323 	wl_proxy_destroy((struct wl_proxy *) seat);
324 	client_disconnect_nocheck(c);
325 }
326 
327 /* all the testcases could be in one TEST, but splitting it
328  * apart is better for debugging when the test fails */
TEST(post_error_to_one_from_two_clients)329 TEST(post_error_to_one_from_two_clients)
330 {
331 	struct display *d = display_create();
332 	struct client_info *cl;
333 
334 	wl_global_create(d->wl_display, &wl_seat_interface,
335 			 1, d, bind_seat);
336 
337 	client_create_noarg(d, post_error_main2);
338 	cl = client_create_noarg(d, post_error_main3);
339 	display_run(d);
340 
341 	/* post error only to the second client */
342 	assert(cl->data);
343 	wl_resource_post_error((struct wl_resource *) cl->data,
344 			       23, "Dummy error");
345 	wl_resource_post_error((struct wl_resource *) cl->data,
346 			       21, "Dummy error (ignore)");
347 
348 	display_resume(d);
349 	display_destroy(d);
350 }
351 
352 /* all the testcases could be in one TEST, but splitting it
353  * apart is better for debugging when the test fails */
TEST(post_error_to_two_clients)354 TEST(post_error_to_two_clients)
355 {
356 	struct display *d = display_create();
357 	struct client_info *cl, *cl2;
358 
359 	wl_global_create(d->wl_display, &wl_seat_interface,
360 			 1, d, bind_seat);
361 
362 	cl = client_create_noarg(d, post_error_main3);
363 	cl2 = client_create_noarg(d, post_error_main3);
364 
365 	display_run(d);
366 
367 	/* Try to send the error to both clients */
368 	assert(cl->data && cl2->data);
369 	wl_resource_post_error((struct wl_resource *) cl->data,
370 			       23, "Dummy error");
371 	wl_resource_post_error((struct wl_resource *) cl->data,
372 			       21, "Dummy error (ignore)");
373 
374 	wl_resource_post_error((struct wl_resource *) cl2->data,
375 			       23, "Dummy error");
376 	wl_resource_post_error((struct wl_resource *) cl2->data,
377 			       21, "Dummy error (ignore)");
378 
379 	display_resume(d);
380 	display_destroy(d);
381 }
382 
383 static void
post_nomem_main(void)384 post_nomem_main(void)
385 {
386 	struct client *c = client_connect();
387 	struct wl_seat *seat = client_get_seat(c);
388 
389 	assert(stop_display(c, 1) == -1);
390 	assert(wl_display_get_error(c->wl_display) == ENOMEM);
391 
392 	wl_proxy_destroy((struct wl_proxy *) seat);
393 	client_disconnect_nocheck(c);
394 }
395 
TEST(post_nomem_tst)396 TEST(post_nomem_tst)
397 {
398 	struct display *d = display_create();
399 	struct client_info *cl;
400 
401 	wl_global_create(d->wl_display, &wl_seat_interface,
402 			 1, d, bind_seat);
403 
404 	cl = client_create_noarg(d, post_nomem_main);
405 	display_run(d);
406 
407 	assert(cl->data);
408 	wl_resource_post_no_memory((struct wl_resource *) cl->data);
409 	display_resume(d);
410 
411 	/* first client terminated. Run it again,
412 	 * but post no memory to client */
413 	cl = client_create_noarg(d, post_nomem_main);
414 	display_run(d);
415 
416 	assert(cl->data);
417 	wl_client_post_no_memory(cl->wl_client);
418 	display_resume(d);
419 
420 	display_destroy(d);
421 }
422 
423 static void
post_implementation_error_main(void)424 post_implementation_error_main(void)
425 {
426 	struct client *c = client_connect();
427 	struct wl_seat *seat = client_get_seat(c);
428 	uint32_t object_id, protocol_error;
429 	const struct wl_interface *interface;
430 
431 	assert(stop_display(c, 1) == -1);
432 	int err = wl_display_get_error(c->wl_display);
433 	fprintf(stderr, "Err is %i\n", err);
434 	assert(err == EPROTO);
435 	protocol_error = wl_display_get_protocol_error(c->wl_display,
436 						       &interface,
437 						       &object_id);
438 	assert(protocol_error == WL_DISPLAY_ERROR_IMPLEMENTATION);
439 	assert(interface == &wl_display_interface);
440 
441 	wl_proxy_destroy((struct wl_proxy *) seat);
442 	client_disconnect_nocheck(c);
443 }
444 
TEST(post_internal_error_tst)445 TEST(post_internal_error_tst)
446 {
447 	struct display *d = display_create();
448 	struct client_info *cl;
449 
450 	wl_global_create(d->wl_display, &wl_seat_interface,
451 			 1, d, bind_seat);
452 
453 	cl = client_create_noarg(d, post_implementation_error_main);
454 	display_run(d);
455 
456 	wl_client_post_implementation_error(cl->wl_client, "Error %i", 20);
457 
458 	display_resume(d);
459 
460 	display_destroy(d);
461 }
462 
463 static void
register_reading(struct wl_display * display)464 register_reading(struct wl_display *display)
465 {
466 	while(wl_display_prepare_read(display) != 0 && errno == EAGAIN)
467 		assert(wl_display_dispatch_pending(display) >= 0);
468 	assert(wl_display_flush(display) >= 0);
469 }
470 
471 /* create thread that will call prepare+read so that
472  * it will block */
473 static pthread_t
create_thread(struct client * c,void * (* func)(void *))474 create_thread(struct client *c, void *(*func)(void*))
475 {
476 	pthread_t thread;
477 
478 	c->display_stopped = 0;
479 	/* func must set display->stopped to 1 before sleeping */
480 	assert(pthread_create(&thread, NULL, func, c) == 0);
481 
482 	/* make sure the thread is sleeping. It's a little bit racy
483 	 * (setting display_stopped to 1 and calling wl_display_read_events)
484 	 * so call usleep once again after the loop ends - it should
485 	 * be sufficient... */
486 	while (c->display_stopped == 0)
487 		test_usleep(500);
488 	test_usleep(10000);
489 
490 	return thread;
491 }
492 
493 static void *
thread_read_error(void * data)494 thread_read_error(void *data)
495 {
496 	struct client *c = data;
497 
498 	register_reading(c->wl_display);
499 
500 	/*
501 	 * Calling the read right now will block this thread
502 	 * until the other thread will read the data.
503 	 * However, after invoking an error, this
504 	 * thread should be woken up or it will block indefinitely.
505 	 */
506 	c->display_stopped = 1;
507 	assert(wl_display_read_events(c->wl_display) == -1);
508 
509 	assert(wl_display_dispatch_pending(c->wl_display) == -1);
510 	assert(wl_display_get_error(c->wl_display));
511 
512 	pthread_exit(NULL);
513 }
514 
515 /* test posting an error in multi-threaded environment. */
516 static void
threading_post_err(void)517 threading_post_err(void)
518 {
519 	DISABLE_LEAK_CHECKS;
520 
521 	struct client *c = client_connect();
522 	pthread_t thread;
523 
524 	/* register read intention */
525 	register_reading(c->wl_display);
526 
527 	/* use this var as an indicator that thread is sleeping */
528 	c->display_stopped = 0;
529 
530 	/* create new thread that will register its intention too */
531 	thread = create_thread(c, thread_read_error);
532 
533 	/* so now we have sleeping thread waiting for a pthread_cond signal.
534 	 * The main thread must call wl_display_read_events().
535 	 * If this call fails, then it won't call broadcast at the
536 	 * end of the function and the sleeping thread will block indefinitely.
537 	 * Make the call fail and watch if libwayland will unblock the thread! */
538 
539 	/* create error on fd, so that wl_display_read_events will fail.
540 	 * The same can happen when server hangs up */
541 	close(wl_display_get_fd(c->wl_display));
542 	/* this read events will fail and will
543 	 * post an error that should wake the sleeping thread
544 	 * and dispatch the incoming events */
545 	assert(wl_display_read_events(c->wl_display) == -1);
546 
547 	/* kill test in 3 seconds. This should be enough time for the
548 	 * thread to exit if it's not blocking. If everything is OK, than
549 	 * the thread was woken up and the test will end before the SIGALRM */
550 	test_set_timeout(3);
551 	pthread_join(thread, NULL);
552 
553 	client_disconnect_nocheck(c);
554 }
555 
TEST(threading_errors_tst)556 TEST(threading_errors_tst)
557 {
558 	struct display *d = display_create();
559 
560 	client_create_noarg(d, threading_post_err);
561 	display_run(d);
562 
563 	display_destroy(d);
564 }
565 
566 static void *
thread_prepare_and_read(void * data)567 thread_prepare_and_read(void *data)
568 {
569 	struct client *c = data;
570 
571 	register_reading(c->wl_display);
572 
573 	c->display_stopped = 1;
574 
575 	assert(wl_display_read_events(c->wl_display) == 0);
576 	assert(wl_display_dispatch_pending(c->wl_display) == 0);
577 
578 	pthread_exit(NULL);
579 }
580 
581 /* test cancel read*/
582 static void
threading_cancel_read(void)583 threading_cancel_read(void)
584 {
585 	DISABLE_LEAK_CHECKS;
586 
587 	struct client *c = client_connect();
588 	pthread_t th1, th2, th3;
589 
590 	register_reading(c->wl_display);
591 
592 	th1 = create_thread(c, thread_prepare_and_read);
593 	th2 = create_thread(c, thread_prepare_and_read);
594 	th3 = create_thread(c, thread_prepare_and_read);
595 
596 	/* all the threads are sleeping, waiting until read or cancel
597 	 * is called. Cancel the read and let the threads proceed */
598 	wl_display_cancel_read(c->wl_display);
599 
600 	/* kill test in 3 seconds. This should be enough time for the
601 	 * thread to exit if it's not blocking. If everything is OK, than
602 	 * the thread was woken up and the test will end before the SIGALRM */
603 	test_set_timeout(3);
604 	pthread_join(th1, NULL);
605 	pthread_join(th2, NULL);
606 	pthread_join(th3, NULL);
607 
608 	client_disconnect(c);
609 }
610 
TEST(threading_cancel_read_tst)611 TEST(threading_cancel_read_tst)
612 {
613 	struct display *d = display_create();
614 
615 	client_create_noarg(d, threading_cancel_read);
616 	display_run(d);
617 
618 	display_destroy(d);
619 }
620 
621 static void
threading_read_eagain(void)622 threading_read_eagain(void)
623 {
624 	DISABLE_LEAK_CHECKS;
625 
626 	struct client *c = client_connect();
627 	pthread_t th1, th2, th3;
628 
629 	register_reading(c->wl_display);
630 
631 	th1 = create_thread(c, thread_prepare_and_read);
632 	th2 = create_thread(c, thread_prepare_and_read);
633 	th3 = create_thread(c, thread_prepare_and_read);
634 
635 	/* All the threads are sleeping, waiting until read or cancel
636 	 * is called. Since we have no data on socket waiting,
637 	 * the wl_connection_read should end up with error and set errno
638 	 * to EAGAIN. Check if the threads are woken up in this case. */
639 	assert(wl_display_read_events(c->wl_display) == 0);
640 	/* errno should be still set to EAGAIN if wl_connection_read
641 	 * set it - check if we're testing the right case */
642 	assert(errno == EAGAIN);
643 
644 	test_set_timeout(3);
645 	pthread_join(th1, NULL);
646 	pthread_join(th2, NULL);
647 	pthread_join(th3, NULL);
648 
649 	client_disconnect(c);
650 }
651 
TEST(threading_read_eagain_tst)652 TEST(threading_read_eagain_tst)
653 {
654 	struct display *d = display_create();
655 	client_create_noarg(d, threading_read_eagain);
656 
657 	display_run(d);
658 
659 	display_destroy(d);
660 }
661 
662 static void *
thread_prepare_and_read2(void * data)663 thread_prepare_and_read2(void *data)
664 {
665 	struct client *c = data;
666 
667 	while(wl_display_prepare_read(c->wl_display) != 0 && errno == EAGAIN)
668 		assert(wl_display_dispatch_pending(c->wl_display) == -1);
669 	assert(wl_display_flush(c->wl_display) == -1);
670 
671 	c->display_stopped = 1;
672 
673 	assert(wl_display_read_events(c->wl_display) == -1);
674 	assert(wl_display_dispatch_pending(c->wl_display) == -1);
675 
676 	pthread_exit(NULL);
677 }
678 
679 static void
threading_read_after_error(void)680 threading_read_after_error(void)
681 {
682 	DISABLE_LEAK_CHECKS;
683 
684 	struct client *c = client_connect();
685 	pthread_t thread;
686 
687 	/* create an error */
688 	close(wl_display_get_fd(c->wl_display));
689 	assert(wl_display_dispatch(c->wl_display) == -1);
690 
691 	/* try to prepare for reading */
692 	while(wl_display_prepare_read(c->wl_display) != 0 && errno == EAGAIN)
693 		assert(wl_display_dispatch_pending(c->wl_display) == -1);
694 	assert(wl_display_flush(c->wl_display) == -1);
695 
696 	assert(pthread_create(&thread, NULL,
697 			      thread_prepare_and_read2, c) == 0);
698 
699 	/* make sure thread is sleeping */
700 	while (c->display_stopped == 0)
701 		test_usleep(500);
702 	test_usleep(10000);
703 
704 	assert(wl_display_read_events(c->wl_display) == -1);
705 
706 	/* kill test in 3 seconds */
707 	test_set_timeout(3);
708 	pthread_join(thread, NULL);
709 
710 	client_disconnect_nocheck(c);
711 }
712 
TEST(threading_read_after_error_tst)713 TEST(threading_read_after_error_tst)
714 {
715 	struct display *d = display_create();
716 
717 	client_create_noarg(d, threading_read_after_error);
718 	display_run(d);
719 
720 	display_destroy(d);
721 }
722 
723 static void
wait_for_error_using_dispatch(struct client * c,struct wl_proxy * proxy)724 wait_for_error_using_dispatch(struct client *c, struct wl_proxy *proxy)
725 {
726 	int ret;
727 
728 	while (true) {
729 		/* Dispatching should eventually hit the protocol error before
730 		 * any other error. */
731 		ret = wl_display_dispatch(c->wl_display);
732 		if (ret == 0) {
733 			continue;
734 		} else {
735 			assert(errno == EPROTO);
736 			break;
737 		}
738 	}
739 
740 	check_pending_error(c, proxy);
741 }
742 
743 static void
wait_for_error_using_prepare_read(struct client * c,struct wl_proxy * proxy)744 wait_for_error_using_prepare_read(struct client *c, struct wl_proxy *proxy)
745 {
746 	int ret = 0;
747 	struct pollfd pfd[2];
748 
749 	while (true) {
750 		while (wl_display_prepare_read(c->wl_display) != 0 &&
751 		      errno == EAGAIN) {
752 			assert(wl_display_dispatch_pending(c->wl_display) >= 0);
753 		}
754 
755 		/* Flush may fail due to EPIPE if the connection is broken, but
756 		 * this must not set a fatal display error because that would
757 		 * result in it being impossible to read a potential protocol
758 		 * error. */
759 		do {
760 			ret = wl_display_flush(c->wl_display);
761 		} while (ret == -1 && (errno == EINTR || errno == EAGAIN));
762 		assert(ret >= 0 || errno == EPIPE);
763 		assert(wl_display_get_error(c->wl_display) == 0);
764 
765 		pfd[0].fd = wl_display_get_fd(c->wl_display);
766 		pfd[0].events = POLLIN;
767 		do {
768 			ret = poll(pfd, 1, -1);
769 		} while (ret == -1 && errno == EINTR);
770 		assert(ret != -1);
771 
772 		/* We should always manage to read the error before the EPIPE
773 		 * comes this way. */
774 		assert(wl_display_read_events(c->wl_display) == 0);
775 
776 		/* Dispatching should eventually hit the protocol error before
777 		 * any other error. */
778 		ret = wl_display_dispatch_pending(c->wl_display);
779 		if (ret == 0) {
780 			continue;
781 		} else {
782 			assert(errno == EPROTO);
783 			break;
784 		}
785 	}
786 
787 	check_pending_error(c, proxy);
788 }
789 
790 static void
check_error_after_epipe(void * data)791 check_error_after_epipe(void *data)
792 {
793 	bool use_dispatch_helpers = *(bool *) data;
794 	struct client *client;
795 	struct wl_seat *seat;
796 	struct wl_callback *callback;
797 
798 	client = client_connect();
799 
800 	/* This will, according to the implementation below, cause the server
801 	 * to post an error. */
802 	seat = client_get_seat(client);
803 	wl_display_flush(client->wl_display);
804 
805 	/* The server will not actually destroy the client until it receives
806 	 * input, so send something to trigger the client destruction. */
807 	callback = wl_display_sync(client->wl_display);
808 	wl_callback_destroy(callback);
809 
810 	/* Sleep some to give the server a chance to react and destroy the
811 	 * client. */
812 	test_usleep(200000);
813 
814 	/* Wait for the protocol error and check that we reached it before
815 	 * EPIPE. */
816 	if (use_dispatch_helpers) {
817 		wait_for_error_using_dispatch(client, (struct wl_proxy *) seat);
818 	} else {
819 		wait_for_error_using_prepare_read(client,
820 						  (struct wl_proxy *) seat);
821 	}
822 
823 	wl_seat_destroy(seat);
824 	client_disconnect_nocheck(client);
825 }
826 
827 static void
bind_seat_and_post_error(struct wl_client * client,void * data,uint32_t version,uint32_t id)828 bind_seat_and_post_error(struct wl_client *client, void *data,
829 			 uint32_t version, uint32_t id)
830 {
831 	struct display *d = data;
832 	struct client_info *ci;
833 	struct wl_resource *resource;
834 
835 	ci = find_client_info(d, client);
836 	assert(ci);
837 
838 	resource = wl_resource_create(client, &wl_seat_interface, version, id);
839 	assert(resource);
840 	ci->data = resource;
841 
842 	wl_resource_post_error(ci->data, 23, "Dummy error");
843 }
844 
TEST(error_code_after_epipe)845 TEST(error_code_after_epipe)
846 {
847 	struct display *d = display_create();
848 	bool use_dispatch_helpers;
849 
850 	wl_global_create(d->wl_display, &wl_seat_interface,
851 			 1, d, bind_seat_and_post_error);
852 
853 	use_dispatch_helpers = true;
854 	client_create(d, check_error_after_epipe, &use_dispatch_helpers);
855 	display_run(d);
856 
857 	use_dispatch_helpers = false;
858 	client_create(d, check_error_after_epipe, &use_dispatch_helpers);
859 	display_run(d);
860 
861 	display_destroy(d);
862 }
863 
864 static void
check_seat_versions(struct wl_seat * seat,uint32_t ev)865 check_seat_versions(struct wl_seat *seat, uint32_t ev)
866 {
867 	struct wl_pointer *pointer;
868 
869 	assert(wl_proxy_get_version((struct wl_proxy *) seat) == ev);
870 	assert(wl_seat_get_version(seat) == ev);
871 
872 	pointer = wl_seat_get_pointer(seat);
873 	assert(wl_pointer_get_version(pointer) == ev);
874 	assert(wl_proxy_get_version((struct wl_proxy *) pointer) == ev);
875 	wl_proxy_destroy((struct wl_proxy *) pointer);
876 }
877 
878 /* Normal client with proxy versions available. */
879 static void
seat_version(void * data)880 seat_version(void *data)
881 {
882 	struct handler_info *hi = data;
883 	struct client *c = client_connect();
884 	struct wl_seat *seat;
885 
886 	/* display proxy should always be version 0 */
887 	assert(wl_proxy_get_version((struct wl_proxy *) c->wl_display) == 0);
888 
889 	seat = client_get_seat_with_info(c, hi);
890 	if (hi->use_unversioned)
891 		check_seat_versions(seat, 0);
892 	else
893 		check_seat_versions(seat, hi->bind_version);
894 
895 	wl_proxy_destroy((struct wl_proxy *) seat);
896 
897 	client_disconnect_nocheck(c);
898 }
899 
TEST(versions)900 TEST(versions)
901 {
902 	struct display *d = display_create();
903 	struct wl_global *global;
904 	int i;
905 
906 	global = wl_global_create(d->wl_display, &wl_seat_interface,
907 				  5, d, bind_seat);
908 
909 	for (i = 1; i <= 5; i++) {
910 		struct handler_info hi;
911 
912 		hi.bind_version = i;
913 		hi.use_unversioned = false;
914 		client_create(d, seat_version, &hi);
915 		hi.use_unversioned = true;
916 		client_create(d, seat_version, &hi);
917 	}
918 
919 	display_run(d);
920 
921 	wl_global_destroy(global);
922 
923 	display_destroy(d);
924 }
925 
926 static void
check_error_on_destroyed_object(void * data)927 check_error_on_destroyed_object(void *data)
928 {
929 	struct client *c;
930 	struct wl_seat *seat;
931 	uint32_t id;
932 	const struct wl_interface *intf;
933 
934 	c = client_connect();
935 	seat = client_get_seat(c);
936 
937 	/* destroy the seat proxy. The display won't know
938 	 * about it yet, so it will post the error as usual */
939 	wl_proxy_destroy((struct wl_proxy *) seat);
940 
941 	/* let display post the error. The error will
942 	 * be caught in stop_display while dispatching */
943 	assert(stop_display(c, 1) == -1);
944 
945 	/* check the returned error. Since the object was destroyed,
946 	 * we don't know the interface and id */
947 	assert(wl_display_get_error(c->wl_display) == EPROTO);
948 	assert(wl_display_get_protocol_error(c->wl_display, &intf, &id) == 23);
949 	assert(intf == NULL);
950 	assert(id == 0);
951 
952 	client_disconnect_nocheck(c);
953 }
954 
TEST(error_on_destroyed_object)955 TEST(error_on_destroyed_object)
956 {
957 	struct client_info *cl;
958 	struct display *d = display_create();
959 
960 	wl_global_create(d->wl_display, &wl_seat_interface,
961 			 1, d, bind_seat);
962 
963 	cl = client_create_noarg(d, check_error_on_destroyed_object);
964 	display_run(d);
965 
966 	/* did client bind to the seat? */
967 	assert(cl->data);
968 
969 	/* post error on the destroyed object */
970 	wl_resource_post_error((struct wl_resource *) cl->data,
971 			       23, "Dummy error");
972 	display_resume(d);
973 	display_destroy(d);
974 }
975 
976 static bool
global_filter(const struct wl_client * client,const struct wl_global * global,void * data)977 global_filter(const struct wl_client *client,
978 	      const struct wl_global *global,
979 	      void *data)
980 {
981 	/* Hide the wl_data_offer interface if no data was provided */
982 	if (wl_global_get_interface(global) == &wl_data_offer_interface)
983 		return data != NULL;
984 
985 	/* Show all the others */
986 	return true;
987 }
988 
989 static void
bind_data_offer(struct wl_client * client,void * data,uint32_t vers,uint32_t id)990 bind_data_offer(struct wl_client *client, void *data,
991 		uint32_t vers, uint32_t id)
992 {
993 	/* Client should not be able to bind to this interface! */
994 	assert(false);
995 }
996 
997 static void
registry_handle_filtered(void * data,struct wl_registry * registry,uint32_t id,const char * intf,uint32_t ver)998 registry_handle_filtered(void *data, struct wl_registry *registry,
999 			 uint32_t id, const char *intf, uint32_t ver)
1000 {
1001 	uint32_t *name = data;
1002 
1003 	if (strcmp (intf, "wl_data_offer") == 0) {
1004 		assert(name);
1005 		*name = id;
1006 	}
1007 }
1008 
1009 static void
registry_handle_remove_filtered(void * data,struct wl_registry * registry,uint32_t id)1010 registry_handle_remove_filtered(void *data, struct wl_registry *registry,
1011 				uint32_t id)
1012 {
1013 	assert(false);
1014 }
1015 
1016 static const struct wl_registry_listener registry_listener_filtered = {
1017 	registry_handle_filtered,
1018 	registry_handle_remove_filtered,
1019 };
1020 
1021 static void
get_globals(void * data)1022 get_globals(void *data)
1023 {
1024 	struct client *c = client_connect();
1025 	struct wl_registry *registry;
1026 
1027 	registry = wl_display_get_registry(c->wl_display);
1028 	wl_registry_add_listener(registry, &registry_listener_filtered, data);
1029 	wl_display_roundtrip(c->wl_display);
1030 
1031 	wl_registry_destroy(registry);
1032 	client_disconnect_nocheck(c);
1033 }
1034 
TEST(filtered_global_is_hidden)1035 TEST(filtered_global_is_hidden)
1036 {
1037 	struct display *d;
1038 	struct wl_global *g;
1039 
1040 	d = display_create();
1041 
1042 	g = wl_global_create(d->wl_display, &wl_data_offer_interface,
1043 		      1, d, bind_data_offer);
1044 	wl_display_set_global_filter(d->wl_display, global_filter, NULL);
1045 
1046 	client_create_noarg(d, get_globals);
1047 	display_run(d);
1048 
1049 	wl_global_destroy(g);
1050 
1051 	display_destroy(d);
1052 }
1053 
1054 static void
get_dynamic_globals(void * data)1055 get_dynamic_globals(void *data)
1056 {
1057 	struct client *c = client_connect();
1058 	struct wl_registry *registry;
1059 
1060 	registry = wl_display_get_registry(c->wl_display);
1061 	wl_registry_add_listener(registry, &registry_listener_filtered, data);
1062 	wl_display_roundtrip(c->wl_display);
1063 
1064 	/* Wait for the server to create a new global */
1065 	assert(stop_display(c, 1) >= 0);
1066 
1067 	/* Check that we don't see it */
1068 	wl_display_roundtrip(c->wl_display);
1069 
1070 	/* Wait for the server to remove that global */
1071 	assert(stop_display(c, 1) >= 0);
1072 
1073 	/* Check that we don't get a global_remove event */
1074 	wl_display_roundtrip(c->wl_display);
1075 
1076 	wl_registry_destroy(registry);
1077 	client_disconnect_nocheck(c);
1078 }
1079 
TEST(filtered_dynamic_global_is_hidden)1080 TEST(filtered_dynamic_global_is_hidden)
1081 {
1082 	struct display *d;
1083 	struct wl_global *g;
1084 
1085 	d = display_create();
1086 	wl_display_set_global_filter(d->wl_display, global_filter, NULL);
1087 
1088 	/* Create a client and let it enumerate the globals */
1089 	client_create_noarg(d, get_dynamic_globals);
1090 	display_run(d);
1091 
1092 	/* Dynamically create a new global */
1093 	g = wl_global_create(d->wl_display, &wl_data_offer_interface,
1094 			     1, d, bind_data_offer);
1095 
1096 	display_resume(d);
1097 
1098 	/* Dynamically remove the global */
1099 	wl_global_destroy(g);
1100 
1101 	display_resume(d);
1102 
1103 	display_destroy(d);
1104 }
1105 
1106 static void
check_bind_error(struct client * c)1107 check_bind_error(struct client *c)
1108 {
1109 	uint32_t errorcode, id;
1110 	int err;
1111 	const struct wl_interface *intf;
1112 
1113 	err = wl_display_get_error(c->wl_display);
1114 	assert(err == EPROTO);
1115 
1116 	errorcode = wl_display_get_protocol_error(c->wl_display, &intf, &id);
1117 	assert(errorcode == WL_DISPLAY_ERROR_INVALID_OBJECT);
1118 }
1119 
1120 static void
force_bind(void * data)1121 force_bind(void *data)
1122 {
1123 	struct client *c = client_connect();
1124 	struct wl_registry *registry;
1125 	void *ptr;
1126 	uint32_t *name = data;
1127 
1128 	registry = wl_display_get_registry(c->wl_display);
1129 
1130 	ptr = wl_registry_bind (registry, *name, &wl_data_offer_interface, 1);
1131 	wl_display_roundtrip(c->wl_display);
1132 	check_bind_error(c);
1133 
1134 	wl_proxy_destroy((struct wl_proxy *) ptr);
1135 	wl_registry_destroy(registry);
1136 
1137 	client_disconnect_nocheck(c);
1138 }
1139 
TEST(bind_fails_on_filtered_global)1140 TEST(bind_fails_on_filtered_global)
1141 {
1142 	struct display *d;
1143 	struct wl_global *g;
1144 	uint32_t *name;
1145 
1146 	/* Create a anonymous shared memory to pass the interface name */
1147 	name = mmap(NULL, sizeof(uint32_t),
1148 		    PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
1149 
1150 	d = display_create();
1151 
1152 	g = wl_global_create(d->wl_display, &wl_data_offer_interface,
1153 			     1, d, bind_data_offer);
1154 	wl_display_set_global_filter(d->wl_display, global_filter, name);
1155 
1156 	client_create(d, get_globals, name);
1157 	*name = 0;
1158 
1159 	display_run(d);
1160 	/* wl_data_offer should be 2 */
1161 	assert(*name == 2);
1162 	wl_display_set_global_filter(d->wl_display, global_filter, NULL);
1163 
1164 	/* Try to bind to the interface name when a global filter is in place */
1165 	client_create(d, force_bind, name);
1166 	display_run(d);
1167 
1168 	wl_global_destroy(g);
1169 
1170 	display_destroy(d);
1171 }
1172 
1173 static void
pre_fd(void * data,struct fd_passer * fdp)1174 pre_fd(void *data, struct fd_passer *fdp)
1175 {
1176 	fd_passer_destroy(fdp);
1177 }
1178 
1179 static void
fd(void * data,struct fd_passer * fdp,int32_t fd)1180 fd(void *data, struct fd_passer *fdp, int32_t fd)
1181 {
1182 	/* We destroyed the resource before this event */
1183 	assert(false);
1184 }
1185 
1186 struct fd_passer_listener fd_passer_listener = {
1187 	pre_fd,
1188 	fd,
1189 };
1190 
1191 static void
zombie_fd_handle_globals(void * data,struct wl_registry * registry,uint32_t id,const char * intf,uint32_t ver)1192 zombie_fd_handle_globals(void *data, struct wl_registry *registry,
1193 			 uint32_t id, const char *intf, uint32_t ver)
1194 {
1195 	struct fd_passer *fdp;
1196 
1197 	if (!strcmp(intf, "fd_passer")) {
1198 		fdp = wl_registry_bind(registry, id, &fd_passer_interface, 1);
1199 		fd_passer_add_listener(fdp, &fd_passer_listener, NULL);
1200 	}
1201 }
1202 
1203 static const struct wl_registry_listener zombie_fd_registry_listener = {
1204 	zombie_fd_handle_globals,
1205 	NULL
1206 };
1207 
1208 static void
zombie_client(void * data)1209 zombie_client(void *data)
1210 {
1211 	struct client *c = client_connect();
1212 	struct wl_registry *registry;
1213 
1214 	registry = wl_display_get_registry(c->wl_display);
1215 	wl_registry_add_listener(registry, &zombie_fd_registry_listener, NULL);
1216 
1217 	/* Gets the registry */
1218 	wl_display_roundtrip(c->wl_display);
1219 
1220 	/* push out the fd_passer bind */
1221 	wl_display_roundtrip(c->wl_display);
1222 
1223 	/* push out our fd_passer.destroy */
1224 	wl_display_roundtrip(c->wl_display);
1225 
1226 	wl_registry_destroy(registry);
1227 
1228 	client_disconnect_nocheck(c);
1229 }
1230 
1231 struct passer_data {
1232 	struct wl_resource *conjoined_passer;
1233 };
1234 
1235 static void
feed_pipe(int fd,char tosend)1236 feed_pipe(int fd, char tosend)
1237 {
1238 	int count;
1239 
1240 	do {
1241 		count = write(fd, &tosend, 1);
1242 	} while (count != 1 && errno == EAGAIN);
1243 	assert(count == 1);
1244 	close(fd);
1245 }
1246 
1247 static void
fd_passer_clobber(struct wl_client * client,struct wl_resource * res)1248 fd_passer_clobber(struct wl_client *client, struct wl_resource *res)
1249 {
1250 	struct passer_data *pdata = wl_resource_get_user_data(res);
1251 	int pipes1[2], pipes2[2], ret;
1252 
1253 	if (pdata->conjoined_passer) {
1254 		ret = pipe(pipes1);
1255 		assert(ret == 0);
1256 		ret = pipe(pipes2);
1257 		assert(ret == 0);
1258 
1259 		wl_resource_queue_event(res, FD_PASSER_FD, pipes1[0]);
1260 		fd_passer_send_fd(pdata->conjoined_passer, pipes2[0]);
1261 		feed_pipe(pipes1[1], '1');
1262 		feed_pipe(pipes2[1], '2');
1263 		close(pipes1[0]);
1264 		close(pipes2[0]);
1265 	}
1266 	wl_resource_destroy(res);
1267 }
1268 
1269 static void
fd_passer_twin(struct wl_client * client,struct wl_resource * res,struct wl_resource * passer)1270 fd_passer_twin(struct wl_client *client, struct wl_resource *res, struct wl_resource *passer)
1271 {
1272 	struct passer_data *pdata = wl_resource_get_user_data(res);
1273 
1274 	pdata->conjoined_passer = passer;
1275 }
1276 
1277 static const struct fd_passer_interface fdp_interface = {
1278 	fd_passer_clobber,
1279 	fd_passer_twin
1280 };
1281 
1282 static void
pdata_destroy(struct wl_resource * res)1283 pdata_destroy(struct wl_resource *res)
1284 {
1285 	struct passer_data *pdata = wl_resource_get_user_data(res);
1286 
1287 	free(pdata);
1288 }
1289 
1290 static void
bind_fd_passer(struct wl_client * client,void * data,uint32_t vers,uint32_t id)1291 bind_fd_passer(struct wl_client *client, void *data,
1292 	       uint32_t vers, uint32_t id)
1293 {
1294 	struct wl_resource *res;
1295 	struct passer_data *pdata;
1296 
1297 	pdata = malloc(sizeof(*pdata));
1298 	assert(pdata);
1299 	pdata->conjoined_passer = NULL;
1300 
1301 	res = wl_resource_create(client, &fd_passer_interface, vers, id);
1302 	wl_resource_set_implementation(res, &fdp_interface, pdata, pdata_destroy);
1303 	assert(res);
1304 	if (vers == 1) {
1305 		fd_passer_send_pre_fd(res);
1306 		fd_passer_send_fd(res, fileno(stdin));
1307 	}
1308 }
1309 
TEST(zombie_fd)1310 TEST(zombie_fd)
1311 {
1312 	struct display *d;
1313 	struct wl_global *g;
1314 
1315 	d = display_create();
1316 
1317 	g = wl_global_create(d->wl_display, &fd_passer_interface,
1318 			     1, d, bind_fd_passer);
1319 
1320 	client_create_noarg(d, zombie_client);
1321 	display_run(d);
1322 
1323 	wl_global_destroy(g);
1324 
1325 	display_destroy(d);
1326 }
1327 
1328 
1329 static void
double_pre_fd(void * data,struct fd_passer * fdp)1330 double_pre_fd(void *data, struct fd_passer *fdp)
1331 {
1332 	assert(false);
1333 }
1334 
1335 static void
double_fd(void * data,struct fd_passer * fdp,int32_t fd)1336 double_fd(void *data, struct fd_passer *fdp, int32_t fd)
1337 {
1338 	char buf;
1339 	int count;
1340 
1341 	do {
1342 		count = read(fd, &buf, 1);
1343 	} while (count != 1 && errno == EAGAIN);
1344 	assert(count == 1);
1345 
1346 	close(fd);
1347 	fd_passer_destroy(fdp);
1348 	assert(buf == '2');
1349 }
1350 
1351 struct fd_passer_listener double_fd_passer_listener = {
1352 	double_pre_fd,
1353 	double_fd,
1354 };
1355 
1356 
1357 static void
double_zombie_fd_handle_globals(void * data,struct wl_registry * registry,uint32_t id,const char * intf,uint32_t ver)1358 double_zombie_fd_handle_globals(void *data, struct wl_registry *registry,
1359 			 uint32_t id, const char *intf, uint32_t ver)
1360 {
1361 	struct fd_passer *fdp1, *fdp2;
1362 
1363 	if (!strcmp(intf, "fd_passer")) {
1364 		fdp1 = wl_registry_bind(registry, id, &fd_passer_interface, 2);
1365 		fd_passer_add_listener(fdp1, &double_fd_passer_listener, NULL);
1366 		fdp2 = wl_registry_bind(registry, id, &fd_passer_interface, 2);
1367 		fd_passer_add_listener(fdp2, &double_fd_passer_listener, NULL);
1368 		fd_passer_conjoin(fdp1, fdp2);
1369 		fd_passer_destroy(fdp1);
1370 	}
1371 }
1372 
1373 static const struct wl_registry_listener double_zombie_fd_registry_listener = {
1374 	double_zombie_fd_handle_globals,
1375 	NULL
1376 };
1377 
1378 static void
double_zombie_client(void * data)1379 double_zombie_client(void *data)
1380 {
1381 	struct client *c = client_connect();
1382 	struct wl_registry *registry;
1383 
1384 	registry = wl_display_get_registry(c->wl_display);
1385 	wl_registry_add_listener(registry, &double_zombie_fd_registry_listener, NULL);
1386 
1387 	/* Gets the registry */
1388 	wl_display_roundtrip(c->wl_display);
1389 
1390 	/* One more so server can respond to conjoin+destroy */
1391 	wl_display_roundtrip(c->wl_display);
1392 
1393 	/* And finally push out our last fd_passer.destroy */
1394 	wl_display_roundtrip(c->wl_display);
1395 
1396 	wl_registry_destroy(registry);
1397 
1398 	client_disconnect_nocheck(c);
1399 }
1400 
TEST(zombie_fd_errant_consumption)1401 TEST(zombie_fd_errant_consumption)
1402 {
1403 	struct display *d;
1404 	struct wl_global *g;
1405 
1406 	d = display_create();
1407 
1408 	g = wl_global_create(d->wl_display, &fd_passer_interface,
1409 			     2, d, bind_fd_passer);
1410 
1411 	client_create_noarg(d, double_zombie_client);
1412 	display_run(d);
1413 
1414 	wl_global_destroy(g);
1415 
1416 	display_destroy(d);
1417 }
1418 
1419 
1420 static void
registry_bind_interface_mismatch_handle_global(void * data,struct wl_registry * registry,uint32_t id,const char * intf,uint32_t ver)1421 registry_bind_interface_mismatch_handle_global(void *data,
1422 					       struct wl_registry *registry,
1423 					       uint32_t id, const char *intf,
1424 					       uint32_t ver)
1425 {
1426 	uint32_t *seat_id_ptr = data;
1427 
1428 	if (strcmp(intf, wl_seat_interface.name) == 0) {
1429 		*seat_id_ptr = id;
1430 	}
1431 }
1432 
1433 static const struct wl_registry_listener bind_interface_mismatch_registry_listener = {
1434 	registry_bind_interface_mismatch_handle_global,
1435 	NULL
1436 };
1437 
1438 static void
registry_bind_interface_mismatch_client(void * data)1439 registry_bind_interface_mismatch_client(void *data)
1440 {
1441 	struct client *c = client_connect();
1442 	struct wl_registry *registry;
1443 	uint32_t seat_id = 0;
1444 	void *ptr;
1445 	int ret;
1446 
1447 	registry = wl_display_get_registry(c->wl_display);
1448 	wl_registry_add_listener(registry,
1449 				 &bind_interface_mismatch_registry_listener,
1450 				 &seat_id);
1451 
1452 	ret = wl_display_roundtrip(c->wl_display);
1453 	assert(ret >= 0);
1454 	assert(seat_id != 0);
1455 
1456 	/* Bind with a different interface */
1457 	ptr = wl_registry_bind(registry, seat_id, &wl_output_interface, 1);
1458 	ret = wl_display_roundtrip(c->wl_display);
1459 	assert(ret < 0);
1460 	check_bind_error(c);
1461 
1462 	wl_proxy_destroy((struct wl_proxy *) ptr);
1463 	wl_registry_destroy(registry);
1464 
1465 	client_disconnect_nocheck(c);
1466 }
1467 
TEST(registry_bind_interface_mismatch)1468 TEST(registry_bind_interface_mismatch)
1469 {
1470 	struct display *d;
1471 	struct wl_global *seat_global;
1472 
1473 	d = display_create();
1474 
1475 	seat_global = wl_global_create(d->wl_display, &wl_seat_interface,
1476 				       1, NULL, NULL);
1477 
1478 	client_create_noarg(d, registry_bind_interface_mismatch_client);
1479 	display_run(d);
1480 
1481 	wl_global_destroy(seat_global);
1482 
1483 	display_destroy(d);
1484 }
1485 
1486 static void
send_overflow_client(void * data)1487 send_overflow_client(void *data)
1488 {
1489 	struct client *c = client_connect();
1490 	int i, err = 0;
1491 	int *pipes = data;
1492 	char tmp = '\0';
1493 	int sock, optval = 16384;
1494 
1495 	/* Limit the send buffer size for the display socket to guarantee
1496 	 * that the test will cause an overflow. */
1497 	sock = wl_display_get_fd(c->wl_display);
1498 	assert(setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &optval, sizeof(optval)) == 0);
1499 
1500 	/* Request to break out of 'display_run' in the main process */
1501 	assert(stop_display(c, 1) >= 0);
1502 
1503 	/* On Linux, the actual socket data + metadata space is twice `optval`;
1504 	 * since each noop request requires 8 bytes, the buffer should overflow
1505 	 * within <=4096 iterations. */
1506 	for (i = 0; i < 1000000; i++) {
1507 		noop_request(c);
1508 		err = wl_display_get_error(c->wl_display);
1509 		if (err)
1510 			break;
1511 	}
1512 
1513 	/* Do not close the pipe file descriptors afterwards, because the leak
1514 	 * check verifies that the initial/final FD counts are the same */
1515 	assert(write(pipes[1], &tmp, sizeof(tmp)) == (ssize_t)sizeof(tmp));
1516 
1517 	/* Expect an error */
1518 	fprintf(stderr, "Send loop failed on try %d, err = %d, %s\n", i, err, strerror(err));
1519 	assert(err == EAGAIN);
1520 
1521 	client_disconnect_nocheck(c);
1522 }
1523 
TEST(send_overflow_disconnection)1524 TEST(send_overflow_disconnection)
1525 {
1526 	struct display *d;
1527 	char tmp;
1528 	int rpipe[2];
1529 	ssize_t ret;
1530 
1531 	assert(pipe(rpipe) != -1);
1532 
1533 	d = display_create();
1534 
1535 	(void) client_create(d, send_overflow_client, &rpipe);
1536 
1537 	/* Close write end of the pipe, so that the later read() call gets
1538 	 * interrupted if the client dies */
1539 	close(rpipe[1]);
1540 
1541 	/* Run the display until the client sends a `stop_display`, then
1542 	 * send a resume message but don't actually look at new messages */
1543 	display_run(d);
1544 	display_post_resume_events(d);
1545 	wl_display_flush_clients(d->wl_display);
1546 
1547 	/* Wait until all noop requests have been sent (read returns 1), or
1548 	 * until client process aborts (read returns 0) */
1549 	do {
1550 		ret = read(rpipe[0], &tmp, sizeof(tmp));
1551 	} while (ret == -1 && errno == EINTR);
1552 	assert(ret != -1);
1553 	close(rpipe[0]);
1554 
1555 	/* For a clean shutdown */
1556 	display_run(d);
1557 
1558 	display_destroy(d);
1559 }
1560 
1561 static void
registry_global_remove_before_handle_global(void * data,struct wl_registry * registry,uint32_t id,const char * intf,uint32_t ver)1562 registry_global_remove_before_handle_global(void *data,
1563 					    struct wl_registry *registry,
1564 					    uint32_t id, const char *intf,
1565 					    uint32_t ver)
1566 {
1567 	uint32_t *id_ptr = data;
1568 
1569 	if (strcmp(intf, wl_seat_interface.name) == 0) {
1570 		assert(*id_ptr == 0);
1571 		*id_ptr = id;
1572 	}
1573 }
1574 
1575 static void
registry_global_remove_before_handle_global_remove(void * data,struct wl_registry * registry,uint32_t id)1576 registry_global_remove_before_handle_global_remove(void *data,
1577 						   struct wl_registry *registry,
1578 						   uint32_t id)
1579 {
1580 	uint32_t *id_ptr = data;
1581 
1582 	if (*id_ptr == id) {
1583 		*id_ptr = 0;
1584 	}
1585 }
1586 
1587 /* This listener expects a uint32_t user data pointer, sets it to the wl_seat
1588  * global ID when receiving a "global" event, and sets it to zero when receiving
1589  * a "global_remove" event. */
1590 static const struct wl_registry_listener global_remove_before_registry_listener = {
1591 	registry_global_remove_before_handle_global,
1592 	registry_global_remove_before_handle_global_remove,
1593 };
1594 
1595 static void
global_remove_before_client(void * data)1596 global_remove_before_client(void *data)
1597 {
1598 	struct client *c = client_connect();
1599 	struct wl_registry *registry;
1600 	uint32_t global_id = 0, saved_global_id;
1601 	struct wl_seat *seat;
1602 	int ret;
1603 
1604 	registry = wl_display_get_registry(c->wl_display);
1605 	wl_registry_add_listener(registry,
1606 				 &global_remove_before_registry_listener,
1607 				 &global_id);
1608 
1609 	ret = wl_display_roundtrip(c->wl_display);
1610 	assert(ret >= 0);
1611 	assert(global_id != 0);
1612 	saved_global_id = global_id;
1613 
1614 	/* Wait for the compositor to remove the global */
1615 	assert(stop_display(c, 1) >= 0);
1616 
1617 	/* Check binding still works after the global has been removed. Also
1618 	 * check we get the global_remove event. */
1619 	seat = wl_registry_bind(registry, saved_global_id, &wl_seat_interface, 1);
1620 	ret = wl_display_roundtrip(c->wl_display);
1621 	assert(ret >= 0);
1622 	assert(global_id == 0);
1623 
1624 	wl_seat_destroy(seat);
1625 	wl_registry_destroy(registry);
1626 
1627 	client_disconnect(c);
1628 }
1629 
1630 static void
registry_global_remove_after_handle_global(void * data,struct wl_registry * registry,uint32_t id,const char * intf,uint32_t ver)1631 registry_global_remove_after_handle_global(void *data,
1632 					   struct wl_registry *registry,
1633 					   uint32_t id, const char *intf,
1634 					   uint32_t ver)
1635 {
1636 	/* Make sure the global isn't advertised anymore after being removed */
1637 	assert(strcmp(intf, wl_seat_interface.name) != 0);
1638 }
1639 
1640 static const struct wl_registry_listener global_remove_after_registry_listener = {
1641 	registry_global_remove_after_handle_global,
1642 	NULL,
1643 };
1644 
1645 static void
global_remove_after_client(void * data)1646 global_remove_after_client(void *data)
1647 {
1648 	struct client *c = client_connect();
1649 	struct wl_registry *registry;
1650 	uint32_t global_id = 0;
1651 	int ret;
1652 
1653 	registry = wl_display_get_registry(c->wl_display);
1654 	wl_registry_add_listener(registry,
1655 				 &global_remove_after_registry_listener,
1656 				 &global_id);
1657 
1658 	ret = wl_display_roundtrip(c->wl_display);
1659 	assert(ret >= 0);
1660 
1661 	wl_registry_destroy(registry);
1662 
1663 	client_disconnect(c);
1664 }
1665 
TEST(global_remove)1666 TEST(global_remove)
1667 {
1668 	struct display *d;
1669 	struct wl_global *global;
1670 
1671 	d = display_create();
1672 
1673 	global = wl_global_create(d->wl_display, &wl_seat_interface,
1674 				  1, d, bind_seat);
1675 
1676 	/* Create a client before removing the global */
1677 	client_create_noarg(d, global_remove_before_client);
1678 
1679 	display_run(d);
1680 
1681 	wl_global_remove(global);
1682 
1683 	/* Create another client after removing the global */
1684 	client_create_noarg(d, global_remove_after_client);
1685 
1686 	display_resume(d);
1687 
1688 	wl_global_destroy(global);
1689 
1690 	display_destroy(d);
1691 }
1692 
1693 static void
terminate_display(void * arg)1694 terminate_display(void *arg)
1695 {
1696 	struct wl_display *wl_display = arg;
1697 	wl_display_terminate(wl_display);
1698 }
1699 
TEST(no_source_terminate)1700 TEST(no_source_terminate)
1701 {
1702 	struct display *d;
1703 	struct wl_event_loop *loop;
1704 
1705 	d = display_create();
1706 	loop = wl_display_get_event_loop(d->wl_display);
1707 
1708 	wl_event_loop_add_idle(loop, terminate_display, d->wl_display);
1709 
1710 	display_run(d);
1711 	display_destroy(d);
1712 }
1713