From beb080ed858f35608cdaed1f9741d121067da42a Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Fri, 17 May 2013 16:46:04 +0300 Subject: [PATCH] tests: add sub-surface tree destruction permutations Add a test for varying the object destruction order in a complex sub-surface tree. This test attemps to fuzz the destruction of a sub-surface tree to make sure the server does not crash on any wl_surface or wl_subsurface destruction sequence. Signed-off-by: Pekka Paalanen --- tests/subsurface-test.c | 202 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) diff --git a/tests/subsurface-test.c b/tests/subsurface-test.c index 8f1fd143..0a210fb6 100644 --- a/tests/subsurface-test.c +++ b/tests/subsurface-test.c @@ -24,6 +24,7 @@ #include "weston-test-client-helper.h" #include "subsurface-client-protocol.h" +#include #define NUM_SUBSURFACES 3 @@ -323,3 +324,204 @@ TEST(test_subsurface_destroy_protocol) client_roundtrip(client); } + +static void +create_subsurface_tree(struct client *client, struct wl_surface **surfs, + struct wl_subsurface **subs, int n) +{ + struct wl_subcompositor *subco; + int i; + + subco = get_subcompositor(client); + + for (i = 0; i < n; i++) + surfs[i] = wl_compositor_create_surface(client->wl_compositor); + + /* + * The tree of sub-surfaces: + * 0 + * / \ + * 1 2 - 10 + * / \ |\ + * 3 5 9 6 + * / / \ + * 4 7 8 + * Surface 0 has no wl_subsurface, others do. + */ + + switch (n) { + default: + assert(0); + break; + +#define SUB_LINK(s,p) \ + subs[s] = wl_subcompositor_get_subsurface(subco, surfs[s], surfs[p]) + + case 11: + SUB_LINK(10, 2); + case 10: + SUB_LINK(9, 2); + case 9: + SUB_LINK(8, 6); + case 8: + SUB_LINK(7, 6); + case 7: + SUB_LINK(6, 2); + case 6: + SUB_LINK(5, 1); + case 5: + SUB_LINK(4, 3); + case 4: + SUB_LINK(3, 1); + case 3: + SUB_LINK(2, 0); + case 2: + SUB_LINK(1, 0); + +#undef SUB_LINK + }; +} + +static void +destroy_subsurface_tree(struct wl_surface **surfs, + struct wl_subsurface **subs, int n) +{ + int i; + + for (i = n; i-- > 0; ) { + if (surfs[i]) + wl_surface_destroy(surfs[i]); + + if (subs[i]) + wl_subsurface_destroy(subs[i]); + } +} + +static int +has_dupe(int *cnt, int n) +{ + int i; + + for (i = 0; i < n; i++) + if (cnt[i] == cnt[n]) + return 1; + + return 0; +} + +/* Note: number of permutations to test is: set_size! / (set_size - NSTEPS)! + */ +#define NSTEPS 3 + +struct permu_state { + int set_size; + int cnt[NSTEPS]; +}; + +static void +permu_init(struct permu_state *s, int set_size) +{ + int i; + + s->set_size = set_size; + for (i = 0; i < NSTEPS; i++) + s->cnt[i] = 0; +} + +static int +permu_next(struct permu_state *s) +{ + int k; + + s->cnt[NSTEPS - 1]++; + + while (1) { + if (s->cnt[0] >= s->set_size) { + return -1; + } + + for (k = 1; k < NSTEPS; k++) { + if (s->cnt[k] >= s->set_size) { + s->cnt[k - 1]++; + s->cnt[k] = 0; + break; + } + + if (has_dupe(s->cnt, k)) { + s->cnt[k]++; + break; + } + } + + if (k == NSTEPS) + return 0; + } +} + +static void +destroy_permu_object(struct wl_surface **surfs, + struct wl_subsurface **subs, int i) +{ + int h = (i + 1) / 2; + + if (i & 1) { + fprintf(stderr, " [sub %2d]", h); + wl_subsurface_destroy(subs[h]); + subs[h] = NULL; + } else { + fprintf(stderr, " [surf %2d]", h); + wl_surface_destroy(surfs[h]); + surfs[h] = NULL; + } +} + +TEST(test_subsurface_destroy_permutations) +{ + /* + * Test wl_surface and wl_subsurface destruction orders in a + * complex tree of sub-surfaces. + * + * In the tree of sub-surfaces, go through every possible + * permutation of destroying all wl_surface and wl_subsurface + * objects. Execpt, to limit running time to a reasonable level, + * execute only the first NSTEPS destructions from each + * permutation, and ignore identical cases. + */ + + const int test_size = 11; + struct client *client; + struct wl_surface *surfs[test_size]; + struct wl_subsurface *subs[test_size]; + struct permu_state per; + int counter = 0; + int i; + + client = client_create(100, 50, 123, 77); + assert(client); + + permu_init(&per, test_size * 2 - 1); + while (permu_next(&per) != -1) { + /* for each permutation of NSTEPS out of test_size */ + memset(surfs, 0, sizeof surfs); + memset(subs, 0, sizeof subs); + + create_subsurface_tree(client, surfs, subs, test_size); + + fprintf(stderr, "permu"); + + for (i = 0; i < NSTEPS; i++) + fprintf(stderr, " %2d", per.cnt[i]); + + for (i = 0; i < NSTEPS; i++) + destroy_permu_object(surfs, subs, per.cnt[i]); + + fprintf(stderr, "\n"); + client_roundtrip(client); + + destroy_subsurface_tree(surfs, subs, test_size); + counter++; + } + + client_roundtrip(client); + fprintf(stderr, "tried %d destroy permutations\n", counter); +}