mirror of
https://github.com/brl/mutter.git
synced 2024-11-27 18:40:40 -05:00
d2c798838e
A client is not allowed to send an empty window geometry, and it is specified that if it does so an error should be raised. Respect this rule, ignore bogus geometries sent by clients with a warning. Also add a soft assert that we don't try to "resend" a configuration that was never sent, as doing so would result in SIGFPE as the geometry scale is 0. This fixes a SIGFPE crash occurring when a client did this. Related: https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/2808 Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/1527 Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1557>
234 lines
7.3 KiB
C
234 lines
7.3 KiB
C
/*
|
|
* Copyright (C) 2019 Red Hat, Inc.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "tests/wayland-unit-tests.h"
|
|
|
|
#include <gio/gio.h>
|
|
#include <wayland-server.h>
|
|
|
|
#include "wayland/meta-wayland.h"
|
|
#include "wayland/meta-wayland-actor-surface.h"
|
|
#include "wayland/meta-wayland-surface.h"
|
|
#include "wayland/meta-wayland-private.h"
|
|
|
|
#include "test-driver-server-protocol.h"
|
|
|
|
typedef struct _WaylandTestClient
|
|
{
|
|
GSubprocess *subprocess;
|
|
char *path;
|
|
GMainLoop *main_loop;
|
|
} WaylandTestClient;
|
|
|
|
static char *
|
|
get_test_client_path (const char *test_client_name)
|
|
{
|
|
return g_test_build_filename (G_TEST_BUILT,
|
|
"src",
|
|
"tests",
|
|
"wayland-test-clients",
|
|
test_client_name,
|
|
NULL);
|
|
}
|
|
|
|
static WaylandTestClient *
|
|
wayland_test_client_new (const char *test_client_name)
|
|
{
|
|
MetaWaylandCompositor *compositor;
|
|
const char *wayland_display_name;
|
|
g_autofree char *test_client_path = NULL;
|
|
g_autoptr (GSubprocessLauncher) launcher = NULL;
|
|
GSubprocess *subprocess;
|
|
GError *error = NULL;
|
|
WaylandTestClient *wayland_test_client;
|
|
|
|
compositor = meta_wayland_compositor_get_default ();
|
|
wayland_display_name = meta_wayland_get_wayland_display_name (compositor);
|
|
test_client_path = get_test_client_path (test_client_name);
|
|
|
|
launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE);
|
|
g_subprocess_launcher_setenv (launcher,
|
|
"WAYLAND_DISPLAY", wayland_display_name,
|
|
TRUE);
|
|
|
|
subprocess = g_subprocess_launcher_spawn (launcher,
|
|
&error,
|
|
test_client_path,
|
|
NULL);
|
|
if (!subprocess)
|
|
{
|
|
g_error ("Failed to launch Wayland test client '%s': %s",
|
|
test_client_path, error->message);
|
|
}
|
|
|
|
wayland_test_client = g_new0 (WaylandTestClient, 1);
|
|
wayland_test_client->subprocess = subprocess;
|
|
wayland_test_client->path = g_strdup (test_client_name);
|
|
wayland_test_client->main_loop = g_main_loop_new (NULL, FALSE);
|
|
|
|
return wayland_test_client;
|
|
}
|
|
|
|
static void
|
|
wayland_test_client_finished (GObject *source_object,
|
|
GAsyncResult *res,
|
|
gpointer user_data)
|
|
{
|
|
WaylandTestClient *wayland_test_client = user_data;
|
|
GError *error = NULL;
|
|
|
|
if (!g_subprocess_wait_finish (wayland_test_client->subprocess,
|
|
res,
|
|
&error))
|
|
{
|
|
g_error ("Failed to wait for Wayland test client '%s': %s",
|
|
wayland_test_client->path, error->message);
|
|
}
|
|
|
|
g_main_loop_quit (wayland_test_client->main_loop);
|
|
}
|
|
|
|
static void
|
|
wayland_test_client_finish (WaylandTestClient *wayland_test_client)
|
|
{
|
|
g_subprocess_wait_async (wayland_test_client->subprocess, NULL,
|
|
wayland_test_client_finished, wayland_test_client);
|
|
|
|
g_main_loop_run (wayland_test_client->main_loop);
|
|
|
|
g_assert_true (g_subprocess_get_successful (wayland_test_client->subprocess));
|
|
|
|
g_main_loop_unref (wayland_test_client->main_loop);
|
|
g_free (wayland_test_client->path);
|
|
g_object_unref (wayland_test_client->subprocess);
|
|
g_free (wayland_test_client);
|
|
}
|
|
|
|
static void
|
|
subsurface_remap_toplevel (void)
|
|
{
|
|
WaylandTestClient *wayland_test_client;
|
|
|
|
wayland_test_client = wayland_test_client_new ("subsurface-remap-toplevel");
|
|
wayland_test_client_finish (wayland_test_client);
|
|
}
|
|
|
|
static void
|
|
subsurface_invalid_subsurfaces (void)
|
|
{
|
|
WaylandTestClient *wayland_test_client;
|
|
|
|
wayland_test_client = wayland_test_client_new ("invalid-subsurfaces");
|
|
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
|
|
"WL: error in client communication*");
|
|
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
|
|
"WL: error in client communication*");
|
|
wayland_test_client_finish (wayland_test_client);
|
|
g_test_assert_expected_messages ();
|
|
}
|
|
|
|
static void
|
|
subsurface_invalid_xdg_shell_actions (void)
|
|
{
|
|
WaylandTestClient *wayland_test_client;
|
|
|
|
wayland_test_client = wayland_test_client_new ("invalid-xdg-shell-actions");
|
|
g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
|
|
"Invalid geometry * set on xdg_surface*");
|
|
wayland_test_client_finish (wayland_test_client);
|
|
g_test_assert_expected_messages ();
|
|
}
|
|
|
|
static void
|
|
on_actor_destroyed (ClutterActor *actor,
|
|
struct wl_resource *callback)
|
|
{
|
|
wl_callback_send_done (callback, 0);
|
|
wl_resource_destroy (callback);
|
|
}
|
|
|
|
static void
|
|
sync_actor_destroy (struct wl_client *client,
|
|
struct wl_resource *resource,
|
|
uint32_t id,
|
|
struct wl_resource *surface_resource)
|
|
{
|
|
MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
|
|
MetaWaylandActorSurface *actor_surface;
|
|
MetaSurfaceActor *actor;
|
|
struct wl_resource *callback;
|
|
|
|
g_assert_nonnull (surface);
|
|
|
|
actor_surface = (MetaWaylandActorSurface *) surface->role;
|
|
g_assert_nonnull (actor_surface);
|
|
|
|
actor = meta_wayland_actor_surface_get_actor (actor_surface);
|
|
g_assert_nonnull (actor);
|
|
|
|
callback = wl_resource_create (client, &wl_callback_interface, 1, id);
|
|
|
|
g_signal_connect (actor, "destroy", G_CALLBACK (on_actor_destroyed),
|
|
callback);
|
|
}
|
|
|
|
static const struct test_driver_interface meta_test_driver_interface = {
|
|
sync_actor_destroy,
|
|
};
|
|
|
|
static void
|
|
bind_test_driver (struct wl_client *client,
|
|
void *data,
|
|
uint32_t version,
|
|
uint32_t id)
|
|
{
|
|
struct wl_resource *resource;
|
|
|
|
resource = wl_resource_create (client, &test_driver_interface,
|
|
version, id);
|
|
wl_resource_set_implementation (resource, &meta_test_driver_interface,
|
|
NULL, NULL);
|
|
}
|
|
|
|
void
|
|
pre_run_wayland_tests (void)
|
|
{
|
|
MetaWaylandCompositor *compositor;
|
|
|
|
compositor = meta_wayland_compositor_get_default ();
|
|
g_assert_nonnull (compositor);
|
|
|
|
if (wl_global_create (compositor->wayland_display,
|
|
&test_driver_interface,
|
|
1,
|
|
NULL, bind_test_driver) == NULL)
|
|
g_error ("Failed to register a global wl-subcompositor object");
|
|
}
|
|
|
|
void
|
|
init_wayland_tests (void)
|
|
{
|
|
g_test_add_func ("/wayland/subsurface/remap-toplevel",
|
|
subsurface_remap_toplevel);
|
|
g_test_add_func ("/wayland/subsurface/invalid-subsurfaces",
|
|
subsurface_invalid_subsurfaces);
|
|
g_test_add_func ("/wayland/subsurface/invalid-xdg-shell-actions",
|
|
subsurface_invalid_xdg_shell_actions);
|
|
}
|