Commit d3251402 authored by Christopher James Halse Rogers's avatar Christopher James Halse Rogers Committed by Pekka Paalanen

proto, server: Add internal server error message. (v2)

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_IMPLEMENTATION error to wl_display so that
such code can notify (and disconnect) clients which hit internal bugs.
While servers can currently abuse other wl_display errors for the same
effect, adding an explicit error code allows clients to tell the
difference between errors which are their fault and errors which are the
server's fault. This is particularly interesting for automated bug
reporting.

v2: Rename error from "internal" to "implementation", in sympathy with
    X11's BadImplementation error.
    Add more justification in the commit message.
Signed-off-by: 's avatarChristopher James Halse Rogers <christopher.halse.rogers@canonical.com>
Acked-by: Pekka Paalanen's avatarPekka Paalanen <pekka.paalanen@collabora.co.uk>
Reviewed-by: Pekka Paalanen's avatarPekka Paalanen <pekka.paalanen@collabora.com>
parent 10c1f37a
Pipeline #16757 passed with stage
in 1 minute and 46 seconds
...@@ -94,6 +94,8 @@ ...@@ -94,6 +94,8 @@
summary="method doesn't exist on the specified interface"/> summary="method doesn't exist on the specified interface"/>
<entry name="no_memory" value="2" <entry name="no_memory" value="2"
summary="server is out of memory"/> summary="server is out of memory"/>
<entry name="implementation" value="3"
summary="implementation error in compositor"/>
</enum> </enum>
<event name="delete_id"> <event name="delete_id">
......
...@@ -185,6 +185,9 @@ display_protocol_error(struct wl_display *display, uint32_t code, ...@@ -185,6 +185,9 @@ display_protocol_error(struct wl_display *display, uint32_t code,
case WL_DISPLAY_ERROR_NO_MEMORY: case WL_DISPLAY_ERROR_NO_MEMORY:
err = ENOMEM; err = ENOMEM;
break; break;
case WL_DISPLAY_ERROR_IMPLEMENTATION:
err = EPROTO;
break;
default: default:
err = EFAULT; err = EFAULT;
} }
......
...@@ -324,6 +324,10 @@ wl_client_get_object(struct wl_client *client, uint32_t id); ...@@ -324,6 +324,10 @@ wl_client_get_object(struct wl_client *client, uint32_t id);
void void
wl_client_post_no_memory(struct wl_client *client); wl_client_post_no_memory(struct wl_client *client);
void
wl_client_post_implementation_error(struct wl_client *client,
const char* msg, ...) WL_PRINTF(2,3);
void void
wl_client_add_resource_created_listener(struct wl_client *client, wl_client_add_resource_created_listener(struct wl_client *client,
struct wl_listener *listener); struct wl_listener *listener);
......
...@@ -650,6 +650,30 @@ wl_client_post_no_memory(struct wl_client *client) ...@@ -650,6 +650,30 @@ wl_client_post_no_memory(struct wl_client *client)
WL_DISPLAY_ERROR_NO_MEMORY, "no memory"); 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 implementation error and disconnect
* the client.
*
* \memberof wl_client
*/
WL_EXPORT void
wl_client_post_implementation_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_IMPLEMENTATION,
msg, ap);
va_end(ap);
}
WL_EXPORT void WL_EXPORT void
wl_resource_post_no_memory(struct wl_resource *resource) wl_resource_post_no_memory(struct wl_resource *resource)
{ {
......
...@@ -419,6 +419,46 @@ TEST(post_nomem_tst) ...@@ -419,6 +419,46 @@ TEST(post_nomem_tst)
display_destroy(d); display_destroy(d);
} }
static void
post_implementation_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_IMPLEMENTATION);
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_implementation_error_main);
display_run(d);
wl_client_post_implementation_error(cl->wl_client, "Error %i", 20);
display_resume(d);
display_destroy(d);
}
static void static void
register_reading(struct wl_display *display) register_reading(struct wl_display *display)
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment