/* * Author: Simon McVittie * Copyright © 2011 Nokia Corporation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * See the included COPYING file for more information. */ #include /* On smcv's laptop, 1e4 iterations didn't always exhibit the bug, but 1e5 * iterations exhibited it 10/10 times in practice. YMMV. */ #define ITERATIONS 100000 static GStaticPrivate sp; static GMutex *mutex; static GCond *cond; static guint i; static volatile gint freed = 0; static void notify (gpointer p) { if (!g_atomic_int_compare_and_exchange (&freed, 0, 1)) { g_error ("someone already freed it after %u iterations", i); } } static gpointer thread_func (gpointer nil) { /* wait for main thread to reach its g_cond_wait call */ g_mutex_lock (mutex); g_static_private_set (&sp, &sp, notify); g_cond_broadcast (cond); g_mutex_unlock (mutex); return nil; } void testcase (void) { g_test_bug ("642026"); g_thread_init (NULL); mutex = g_mutex_new (); cond = g_cond_new (); g_mutex_lock (mutex); for (i = 0; i < ITERATIONS; i++) { GThread *t1; g_static_private_init (&sp); freed = 0; t1 = g_thread_create (thread_func, NULL, TRUE, NULL); /* wait for t1 to set up its thread-private data */ g_cond_wait (cond, mutex); /* exercise the bug, by racing with t1 to free the private data */ g_static_private_free (&sp); g_thread_join (t1); } g_cond_free (cond); g_mutex_unlock (mutex); g_mutex_free (mutex); } int main (int argc, char **argv) { g_test_init (&argc, &argv, NULL); g_test_bug_base ("https://bugzilla.gnome.org/show_bug.cgi?id="); #ifdef G_ERRORCHECK_MUTEXES g_test_add_func ("/glib/642026-ec", testcase); #else g_test_add_func ("/glib/642026", testcase); #endif return g_test_run (); }