From: Christopher James Halse Rogers <christopher.halse.rog...@canonical.com>

Many languages such as C++ or Rust have an unwinding error-reporting
mechanism. Code in these languages can (and must!) wrap request handling
callbacks in unwind guards to avoid undefined behaviour.

As a consequence such code will detect internal server errors, but have
no way to communicate such failures to the client.

This adds a WL_DISPLAY_ERROR_INTERNAL error to wl_display so that
such code can notify (and disconnect) client which hit internal bugs.

Signed-off-by: Christopher James Halse Rogers 
<christopher.halse.rog...@canonical.com>
---
 protocol/wayland.xml      |  2 ++
 src/wayland-client.c      |  3 +++
 src/wayland-server-core.h |  4 ++++
 src/wayland-server.c      | 23 +++++++++++++++++++++++
 tests/display-test.c      | 40 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 72 insertions(+)

diff --git a/protocol/wayland.xml b/protocol/wayland.xml
index b5662e0..1db31a6 100644
--- a/protocol/wayland.xml
+++ b/protocol/wayland.xml
@@ -94,6 +94,8 @@
             summary="method doesn't exist on the specified interface"/>
       <entry name="no_memory" value="2"
             summary="server is out of memory"/>
+      <entry name="internal" value="3"
+            summary="internal server error"/>
     </enum>
 
     <event name="delete_id">
diff --git a/src/wayland-client.c b/src/wayland-client.c
index c1369b8..7c442b1 100644
--- a/src/wayland-client.c
+++ b/src/wayland-client.c
@@ -192,6 +192,9 @@ display_protocol_error(struct wl_display *display, uint32_t 
code,
                case WL_DISPLAY_ERROR_NO_MEMORY:
                        err = ENOMEM;
                        break;
+               case WL_DISPLAY_ERROR_INTERNAL:
+                       err = EPROTO;
+                       break;
                default:
                        err = EFAULT;
                }
diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h
index 2e725d9..7137da6 100644
--- a/src/wayland-server-core.h
+++ b/src/wayland-server-core.h
@@ -324,6 +324,10 @@ wl_client_get_object(struct wl_client *client, uint32_t 
id);
 void
 wl_client_post_no_memory(struct wl_client *client);
 
+void
+wl_client_post_internal_error(struct wl_client *client,
+                             const char* msg, ...) WL_PRINTF(2,3);
+
 void
 wl_client_add_resource_created_listener(struct wl_client *client,
                                         struct wl_listener *listener);
diff --git a/src/wayland-server.c b/src/wayland-server.c
index 00c93f7..6317f8f 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -650,6 +650,29 @@ wl_client_post_no_memory(struct wl_client *client)
                               WL_DISPLAY_ERROR_NO_MEMORY, "no memory");
 }
 
+/** Report an internal server error
+ *
+ * \param client The client object
+ * \param msg A printf-style format string
+ * \param ... Format string arguments
+ *
+ * Report an unspecified internal error and disconnect the client.
+ *
+ * \memberof wl_client
+ */
+WL_EXPORT void
+wl_client_post_internal_error(struct wl_client *client,
+                             char const *msg, ...)
+{
+       va_list ap;
+
+       va_start(ap, msg);
+       wl_resource_post_error_vargs(client->display_resource,
+                                    WL_DISPLAY_ERROR_INTERNAL,
+                                    msg, ap);
+       va_end(ap);
+}
+
 WL_EXPORT void
 wl_resource_post_no_memory(struct wl_resource *resource)
 {
diff --git a/tests/display-test.c b/tests/display-test.c
index 9b49a0e..63f8b5a 100644
--- a/tests/display-test.c
+++ b/tests/display-test.c
@@ -419,6 +419,46 @@ TEST(post_nomem_tst)
        display_destroy(d);
 }
 
+static void
+post_internal_error_main(void)
+{
+       struct client *c = client_connect();
+       struct wl_seat *seat = client_get_seat(c);
+       uint32_t object_id, protocol_error;
+       const struct wl_interface *interface;
+
+       assert(stop_display(c, 1) == -1);
+       int err = wl_display_get_error(c->wl_display);
+       fprintf(stderr, "Err is %i\n", err);
+       assert(err == EPROTO);
+       protocol_error = wl_display_get_protocol_error(c->wl_display,
+                                                      &interface,
+                                                      &object_id);
+       assert(protocol_error == WL_DISPLAY_ERROR_INTERNAL);
+       assert(interface == &wl_display_interface);
+
+       wl_proxy_destroy((struct wl_proxy *) seat);
+       client_disconnect_nocheck(c);
+}
+
+TEST(post_internal_error_tst)
+{
+       struct display *d = display_create();
+       struct client_info *cl;
+
+       wl_global_create(d->wl_display, &wl_seat_interface,
+                        1, d, bind_seat);
+
+       cl = client_create_noarg(d, post_internal_error_main);
+       display_run(d);
+
+       wl_client_post_internal_error(cl->wl_client, "Error %i", 20);
+
+       display_resume(d);
+
+       display_destroy(d);
+}
+
 static void
 register_reading(struct wl_display *display)
 {
-- 
2.15.1

_______________________________________________
wayland-devel mailing list
wayland-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to