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, ®istry_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, ®istry_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, ®istry_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