Control: reassign -1 clutter-1.0-tests
Control: severity -1 serious

We were trying so hard to solve this in either gcc-9 or libglib2.0-0
that we didn't consider whether it could be a clutter bug. (It is.)

On Fri, 12 Jul 2019 at 11:16:53 +0100, Iain Lane wrote:
> Here's the bit of code.
> 
>   
> https://sources.debian.org/src/clutter-1.0/1.26.2+dfsg-10/tests/conform/actor-offscreen-redirect.c/#L172
> 
> It's adding some stuff to a main loop and expecting it to finish when a
> particular signal handler is called.
...
> Things which make it work again
> 
>   - Building glib2.0 w/gcc-9 -O1 (and -O0)
>   - Building w/gcc-8

This appears to have been because building gtestutils.c with different
optimizations results in different junk being left on the stack afterwards.
When running the clutter test under valgrind, we get:

# Start of actor tests
# Start of offscreen tests
==13864== Conditional jump or move depends on uninitialised value(s)
==13864==    at 0x10AD7C: actor_offscreen_redirect 
(actor-offscreen-redirect.c:331)
==13864==    by 0x10AD7C: actor_offscreen_redirect 
(actor-offscreen-redirect.c:299)
==13864==    by 0x492F889: clutter_test_func_wrapper (clutter-test-utils.c:138)
==13864==    by 0x4B6F3BD: ??? (in 
/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.6000.6)

This is the variable 'data' here:

> static void
> actor_offscreen_redirect (void)
> {
>   Data data;
>
>   ... data.was_painted is never initialized ...
>
>   while (!data.was_painted)
>     g_main_context_iteration (NULL, FALSE);
> }

It seems that data.was_painted was intended to be initialized to FALSE
(all-zeroes), but this never actually happened.

If the uninitialized value of data.was_painted happens to be nonzero,
this results in basically the entire test being skipped - we never enter
the main loop, and never have the opportunity for the test to hang while
waiting for a paint signal that will never happen.

Adding some debug code to hexdump the contents of the data struct reveals
that gcc-9 -O1, or gcc-9 -O2 with -fno-tree-pre, fairly reliably fills
data.was_painted with a nonzero value, so most of the test is effectively
never run. gcc-9 -O2 fills it with zeroes, so the test runs. The paint
signal never happens (at least in my testing) and the test hangs.

The attached is probably a good starting point for someone who has some
sort of understanding of Clutter to start to investigate this.

    smcv
diff --git a/tests/conform/actor-offscreen-redirect.c b/tests/conform/actor-offscreen-redirect.c
index f47af3617..44b2e43c6 100644
--- a/tests/conform/actor-offscreen-redirect.c
+++ b/tests/conform/actor-offscreen-redirect.c
@@ -150,25 +150,37 @@ verify_results (Data *data,
   g_free (pixel);
 }
 
+static void
+paint_handler_cb (GMainLoop *main_loop,
+                  gpointer nil)
+{
+  g_debug ("in paint_handler_cb");
+  g_main_loop_quit (main_loop);
+}
+
 static void
 verify_redraw (Data *data, int expected_paint_count)
 {
   GMainLoop *main_loop = g_main_loop_new (NULL, TRUE);
   guint paint_handler;
 
+  g_debug ("in verify_redraw");
+
   paint_handler = g_signal_connect_data (data->stage,
                                          "paint",
-                                         G_CALLBACK (g_main_loop_quit),
+                                         G_CALLBACK (paint_handler_cb),
                                          main_loop,
                                          NULL,
                                          G_CONNECT_SWAPPED | G_CONNECT_AFTER);
 
   /* Queue a redraw on the stage */
+  g_debug ("queueing redraw");
   clutter_actor_queue_redraw (data->stage);
 
   data->foo_actor->paint_count = 0;
 
   /* Wait for it to paint */
+  g_debug ("running main loop");
   g_main_loop_run (main_loop);
 
   g_signal_handler_disconnect (data->stage, paint_handler);
@@ -181,6 +193,8 @@ run_verify (gpointer user_data)
 {
   Data *data = user_data;
 
+  g_debug ("in run_verify");
+
   group_has_overlaps = FALSE;
 
   /* By default the actor shouldn't be redirected so the redraw should
@@ -298,7 +312,7 @@ run_verify (gpointer user_data)
 static void
 actor_offscreen_redirect (void)
 {
-  Data data;
+  Data data = {};
 
   if (!cogl_features_available (COGL_FEATURE_OFFSCREEN))
     return;

Reply via email to