1 /*
2 * Author: Simon McVittie <simon.mcvittie@collabora.co.uk>
3 * Copyright © 2011 Nokia Corporation
4 *
5 * SPDX-License-Identifier: LGPL-2.1-or-later
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * See the included COPYING file for more information.
13 */
14
15 #ifndef GLIB_DISABLE_DEPRECATION_WARNINGS
16 #define GLIB_DISABLE_DEPRECATION_WARNINGS
17 #endif
18
19 #include <glib.h>
20
21 static GStaticPrivate sp;
22 static GMutex *mutex;
23 static GCond *cond;
24 static guint i;
25
26 static gint freed = 0; /* (atomic) */
27
28 static void
29 notify (gpointer p)
30 {
31 if (!g_atomic_int_compare_and_exchange (&freed, 0, 1))
32 {
33 g_error ("someone already freed it after %u iterations", i);
34 }
35 }
36
37 static gpointer thread_func (gpointer nil)
38 {
39 /* wait for main thread to reach its g_cond_wait call */
40 g_mutex_lock (mutex);
41
42 g_static_private_set (&sp, &sp, notify);
43 g_cond_broadcast (cond);
44 g_mutex_unlock (mutex);
45
46 return nil;
47 }
48
49 static void
50 testcase (void)
51 {
52 /* On smcv's laptop, 1e4 iterations didn't always exhibit the bug, but 1e5
53 * iterations exhibited it 10/10 times in practice. YMMV.
54 *
55 * If running with `-m slow` we want to try hard to reproduce the bug 10/10
56 * times. However, as of 2022 this takes around 240s on a CI machine, which
57 * is a long time to tie up those resources to verify that a bug fixed 10
58 * years ago is still fixed.
59 *
60 * So if running without `-m slow`, try 100× less hard to reproduce the bug,
61 * and rely on the fact that this is run under CI often enough to have a good
62 * chance of reproducing the bug in 1% of CI runs. */
63 const guint n_iterations = g_test_slow () ? 100000 : 1000;
64
65 g_test_bug ("https://bugzilla.gnome.org/show_bug.cgi?id=642026");
66
67 mutex = g_mutex_new ();
68 cond = g_cond_new ();
69
70 g_mutex_lock (mutex);
71
72 for (i = 0; i < n_iterations; i++)
73 {
74 GThread *t1;
75
76 g_static_private_init (&sp);
77 g_atomic_int_set (&freed, 0);
78
79 t1 = g_thread_create (thread_func, NULL, TRUE, NULL);
80 g_assert (t1 != NULL);
81
82 /* wait for t1 to set up its thread-private data */
83 g_cond_wait (cond, mutex);
84
85 /* exercise the bug, by racing with t1 to free the private data */
86 g_static_private_free (&sp);
87 g_thread_join (t1);
88 }
89
90 g_cond_free (cond);
91 g_mutex_unlock (mutex);
92 g_mutex_free (mutex);
93 }
94
95 int
96 main (int argc,
97 char **argv)
98 {
99 g_test_init (&argc, &argv, NULL);
100
101 g_test_add_func ("/glib/642026", testcase);
102
103 return g_test_run ();
104 }