]> git.ipfire.org Git - thirdparty/dbus.git/commitdiff
Add unit tests for platform-specific mutex implementation.
authorRalf Habacker <ralf.habacker@freenet.de>
Wed, 2 Mar 2022 12:17:10 +0000 (13:17 +0100)
committerRalf Habacker <ralf.habacker@freenet.de>
Sun, 1 May 2022 17:52:48 +0000 (19:52 +0200)
The tests are enabled with the embedded tests; the required
low-level functions from the dbus library are decorated with
DBUS_EMBEDDED_TESTS_EXPORT to indicate the appropriate usage.

On Windows, all tests are run; on unix-like operating systems,
individual tests are disabled:
- the tests on #NULL pointers of type DBus[C|R]Mutex, since they
  point to a data structure and would cause a segment violation
  when accessed.
- the multiple lock test for type DBusCMutex, since it would block
  the current thread.

Since the whole point of "rmutex" is to be able to lock multiple
times, the "rmutex double lock" test is enabled on unix-like
operating systems too.

Signed-off-by: Ralf Habacker <ralf.habacker@freenet.de>
dbus/dbus-internals.c
dbus/dbus-internals.h
dbus/dbus-threads-internal.h
test/CMakeLists.txt
test/Makefile.am
test/test-platform-mutex.c [new file with mode: 0644]

index ab498b1592b37e754dfc9a52e6b060eb8d0feaae..ea0ffdd57d44e6f29cd4377cbe2e71ce500d2194 100644 (file)
@@ -195,6 +195,13 @@ static dbus_bool_t warn_initted = FALSE;
 static dbus_bool_t fatal_warnings = FALSE;
 static dbus_bool_t fatal_warnings_on_check_failed = TRUE;
 
+static int check_failed_count = 0;
+
+int _dbus_get_check_failed_count (void)
+{
+  return check_failed_count;
+}
+
 static void
 init_warnings(void)
 {
@@ -221,6 +228,8 @@ init_warnings(void)
             }
         }
 
+      check_failed_count = 0;
+
       warn_initted = TRUE;
     }
 }
@@ -288,6 +297,8 @@ _dbus_warn_check_failed(const char *format,
       fflush (stderr);
       _dbus_abort ();
     }
+  else
+    check_failed_count++;
 }
 
 #ifdef DBUS_ENABLE_VERBOSE_MODE
index 1ca0065d7f8bd28d444237e06e7a0d16ec96e5cf..96df3ff70a6446c270a925d7d84f919fd9911505 100644 (file)
@@ -49,6 +49,9 @@ void _dbus_warn_return_if_fail (const char *function,
                                 const char *file,
                                 int line);
 
+DBUS_EMBEDDED_TESTS_EXPORT
+int _dbus_get_check_failed_count (void);
+
 #if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
 #define _DBUS_FUNCTION_NAME __func__
 #elif defined(__GNUC__) || defined(_MSC_VER)
index aa7810acfea4975d87dd55b9c5e469dfdeef27a8..56d169b33897af5c6aecea0c900e691b524adad6 100644 (file)
@@ -81,9 +81,13 @@ void         _dbus_condvar_free_at_location  (DBusCondVar      **location_p);
  *
  * @return  mutex instance or #NULL on OOM
  */
+DBUS_EMBEDDED_TESTS_EXPORT
 DBusRMutex  *_dbus_platform_rmutex_new       (void);
+DBUS_EMBEDDED_TESTS_EXPORT
 void         _dbus_platform_rmutex_free      (DBusRMutex       *mutex);
+DBUS_EMBEDDED_TESTS_EXPORT
 void         _dbus_platform_rmutex_lock      (DBusRMutex       *mutex);
+DBUS_EMBEDDED_TESTS_EXPORT
 void         _dbus_platform_rmutex_unlock    (DBusRMutex       *mutex);
 
 /**
@@ -91,9 +95,13 @@ void         _dbus_platform_rmutex_unlock    (DBusRMutex       *mutex);
  *
  * @return  mutex instance or #NULL on OOM
  */
+DBUS_EMBEDDED_TESTS_EXPORT
 DBusCMutex  *_dbus_platform_cmutex_new       (void);
+DBUS_EMBEDDED_TESTS_EXPORT
 void         _dbus_platform_cmutex_free      (DBusCMutex       *mutex);
+DBUS_EMBEDDED_TESTS_EXPORT
 void         _dbus_platform_cmutex_lock      (DBusCMutex       *mutex);
+DBUS_EMBEDDED_TESTS_EXPORT
 void         _dbus_platform_cmutex_unlock    (DBusCMutex       *mutex);
 
 DBusCondVar* _dbus_platform_condvar_new      (void);
index 4689c78b53be32b3509f76afeed2021252cbfe9a..864d078bef00bec543b0c91591b6e07ab91a30a5 100644 (file)
@@ -144,6 +144,8 @@ if(DBUS_ENABLE_EMBEDDED_TESTS)
     add_test_executable(test-misc-internals "${SOURCES}" dbus-testutils)
     set_target_properties(test-misc-internals PROPERTIES COMPILE_FLAGS ${DBUS_INTERNAL_CLIENT_DEFINITIONS})
 
+    add_test_executable(test-platform-mutex test-platform-mutex.c ${DBUS_INTERNAL_LIBRARIES} dbus-testutils)
+
     set(SOURCES bus/main.c)
     add_test_executable(test-bus "${SOURCES}" dbus-daemon-internal dbus-testutils ${EXPAT_LIBRARIES})
     set_target_properties(test-bus PROPERTIES COMPILE_FLAGS ${DBUS_INTERNAL_CLIENT_DEFINITIONS})
index d013dd875a56fa05785012fc1e51fc73a6108ede..e89d8ad4d4d64178e33bdeb6eb0aad2625c560f9 100644 (file)
@@ -85,6 +85,7 @@ TEST_BINARIES               += test-spawn
 endif
 
 uninstallable_test_programs += \
+       test-platform-mutex \
        test-bus \
        test-bus-dispatch \
        test-bus-dispatch-sha1 \
@@ -256,6 +257,12 @@ test_misc_internals_SOURCES = \
        $(NULL)
 test_misc_internals_LDADD = libdbus-testutils.la
 
+test_platform_mutex_SOURCES = test-platform-mutex.c
+test_platform_mutex_LDADD = \
+       $(top_builddir)/dbus/libdbus-internal.la \
+       libdbus-testutils.la \
+       $(NULL)
+
 EXTRA_DIST += dbus-test-runner
 
 testexecdir = $(libexecdir)/installed-tests/dbus
diff --git a/test/test-platform-mutex.c b/test/test-platform-mutex.c
new file mode 100644 (file)
index 0000000..ba2cb35
--- /dev/null
@@ -0,0 +1,279 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* test-platform-mutex.c
+ *
+ * Copyright © 2022 Ralf Habacker <ralf.habacker@freenet.de>
+ * SPDX-License-Identifier: AFL-2.1 or GPL-2.0-or-later
+
+ * Licensed under the Academic Free License version 2.1
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+#include <config.h>
+
+#include "dbus/dbus-internals.h"
+#include "dbus/dbus-spawn.h"
+#include "dbus/dbus-sysdeps.h"
+#include "dbus/dbus-test.h"
+#include "test/test-utils.h"
+
+#define fail_if_mutex_is_null(a) if (a == NULL) _dbus_test_fatal ("Could not create cmutex")
+
+
+static dbus_bool_t
+_dbus_check_cmutex_new (const char *test_data_dir _DBUS_GNUC_UNUSED)
+{
+  DBusCMutex *mutex = NULL;
+  int count;
+
+  count = _dbus_get_check_failed_count ();
+  mutex = _dbus_platform_cmutex_new ();
+  fail_if_mutex_is_null (mutex);
+  _dbus_platform_cmutex_free (mutex);
+  return _dbus_get_check_failed_count () == count;
+}
+
+static dbus_bool_t
+_dbus_check_cmutex_lock (const char *test_data_dir _DBUS_GNUC_UNUSED)
+{
+  DBusCMutex *mutex = NULL;
+  int count;
+
+  count = _dbus_get_check_failed_count ();
+  mutex = _dbus_platform_cmutex_new ();
+  fail_if_mutex_is_null (mutex);
+  _dbus_platform_cmutex_lock (mutex);
+  _dbus_platform_cmutex_unlock (mutex);
+  _dbus_platform_cmutex_free (mutex);
+  return _dbus_get_check_failed_count () == count;
+}
+
+#ifdef DBUS_WIN
+static dbus_bool_t
+_dbus_check_cmutex_lock_null_pointer (const char *test_data_dir _DBUS_GNUC_UNUSED)
+{
+  DBusCMutex *mutex = NULL;
+  int count;
+
+  count = _dbus_get_check_failed_count ();
+  _dbus_platform_cmutex_lock (mutex);
+  return _dbus_get_check_failed_count () - count == 1;
+}
+
+static dbus_bool_t
+_dbus_check_cmutex_double_lock (const char *test_data_dir _DBUS_GNUC_UNUSED)
+{
+  DBusCMutex *mutex = NULL;
+  int count;
+
+  count = _dbus_get_check_failed_count ();
+  mutex = _dbus_platform_cmutex_new ();
+  fail_if_mutex_is_null (mutex);
+  _dbus_platform_cmutex_lock (mutex);
+  _dbus_platform_cmutex_lock (mutex);
+  _dbus_platform_cmutex_unlock (mutex);
+  _dbus_platform_cmutex_unlock (mutex);
+  _dbus_platform_cmutex_free (mutex);
+  return _dbus_get_check_failed_count () == count;
+}
+
+static dbus_bool_t
+_dbus_check_cmutex_unlock_null_pointer (const char *test_data_dir _DBUS_GNUC_UNUSED)
+{
+  DBusCMutex *mutex = NULL;
+  int count;
+
+  count = _dbus_get_check_failed_count ();
+  _dbus_platform_cmutex_unlock (mutex);
+  return _dbus_get_check_failed_count () - count == 1;
+}
+
+static dbus_bool_t
+_dbus_check_cmutex_null_free (const char *test_data_dir _DBUS_GNUC_UNUSED)
+{
+  DBusCMutex *mutex = NULL;
+  int count;
+
+  count = _dbus_get_check_failed_count ();
+  _dbus_platform_cmutex_free (mutex);  /* programming error (NULL isn't a mutex) */
+  return _dbus_get_check_failed_count () - count == 1;
+}
+
+static dbus_bool_t
+_dbus_check_cmutex_double_free (const char *test_data_dir _DBUS_GNUC_UNUSED)
+{
+  DBusCMutex *mutex = NULL;
+  int count;
+
+  mutex = _dbus_platform_cmutex_new ();
+  fail_if_mutex_is_null (mutex);
+  count = _dbus_get_check_failed_count ();
+  _dbus_platform_cmutex_free (mutex);
+  if (_dbus_get_check_failed_count () - count > 0)
+    {
+      _dbus_test_not_ok ("free'ing mutex failed");
+      return FALSE;
+    }
+  _dbus_platform_cmutex_free (mutex);
+  return _dbus_get_check_failed_count () - count == 1;
+}
+#else
+/*
+ * #NULL pointers of type DBusCMutex cannot be tested on unix-like
+ * operating systems, because they are pointing to a data structure
+ * and would cause a segment violation when accessed.
+ */
+#endif
+
+static dbus_bool_t
+_dbus_check_rmutex_new (const char *test_data_dir _DBUS_GNUC_UNUSED)
+{
+  DBusRMutex *mutex = NULL;
+  int count;
+
+  count = _dbus_get_check_failed_count ();
+  mutex = _dbus_platform_rmutex_new ();
+  fail_if_mutex_is_null (mutex);
+  _dbus_platform_rmutex_free (mutex);
+  return _dbus_get_check_failed_count () == count;
+}
+
+static dbus_bool_t
+_dbus_check_rmutex_lock (const char *test_data_dir _DBUS_GNUC_UNUSED)
+{
+  DBusRMutex *mutex = NULL;
+  int count;
+
+  count = _dbus_get_check_failed_count ();
+  mutex = _dbus_platform_rmutex_new ();
+  fail_if_mutex_is_null (mutex);
+  _dbus_platform_rmutex_lock (mutex);
+  _dbus_platform_rmutex_unlock (mutex);
+  _dbus_platform_rmutex_free (mutex);
+  return _dbus_get_check_failed_count () == count;
+}
+#ifdef DBUS_WIN
+static dbus_bool_t
+_dbus_check_rmutex_lock_null_pointer (const char *test_data_dir _DBUS_GNUC_UNUSED)
+{
+  DBusRMutex *mutex = NULL;
+  int count;
+
+  count = _dbus_get_check_failed_count ();
+  _dbus_platform_rmutex_lock (mutex);
+  return _dbus_get_check_failed_count () - count == 1;
+}
+#endif
+
+static dbus_bool_t
+_dbus_check_rmutex_double_lock (const char *test_data_dir _DBUS_GNUC_UNUSED)
+{
+  DBusRMutex *mutex = NULL;
+  int count;
+
+  count = _dbus_get_check_failed_count ();
+  mutex = _dbus_platform_rmutex_new ();
+  fail_if_mutex_is_null (mutex);
+  _dbus_platform_rmutex_lock (mutex);
+  _dbus_platform_rmutex_lock (mutex);
+  _dbus_platform_rmutex_unlock (mutex);
+  _dbus_platform_rmutex_unlock (mutex);
+  _dbus_platform_rmutex_free (mutex);
+  return _dbus_get_check_failed_count () == count;
+}
+
+#ifdef DBUS_WIN
+static dbus_bool_t
+_dbus_check_rmutex_unlock_null_pointer (const char *test_data_dir _DBUS_GNUC_UNUSED)
+{
+  DBusRMutex *mutex = NULL;
+  int count;
+
+  count = _dbus_get_check_failed_count ();
+  _dbus_platform_rmutex_unlock (mutex);
+  return _dbus_get_check_failed_count () - count == 1;
+}
+
+static dbus_bool_t
+_dbus_check_rmutex_null_free (const char *test_data_dir _DBUS_GNUC_UNUSED)
+{
+  DBusRMutex *mutex = NULL;
+  int count;
+
+  count = _dbus_get_check_failed_count ();
+  _dbus_platform_rmutex_free (mutex);  /* programming error (NULL isn't a mutex) */
+  return _dbus_get_check_failed_count () - count == 1;
+}
+
+static dbus_bool_t
+_dbus_check_rmutex_double_free (const char *test_data_dir _DBUS_GNUC_UNUSED)
+{
+  DBusRMutex *mutex = NULL;
+  int count;
+
+  mutex = _dbus_platform_rmutex_new ();
+  fail_if_mutex_is_null (mutex);
+  count = _dbus_get_check_failed_count ();
+  _dbus_platform_rmutex_free (mutex);
+  if (_dbus_get_check_failed_count () - count > 0)
+    {
+      _dbus_test_not_ok ("free'ing mutex failed");
+      return FALSE;
+    }
+  _dbus_platform_rmutex_free (mutex);
+  return _dbus_get_check_failed_count () - count == 1;
+}
+#else
+/*
+ * #NULL pointers of type DBusRMutex cannot be tested on unix-like
+ * operating systems, because they are pointing to a data structure
+ * and would cause a segment violation when accessed.
+ */
+#endif
+
+static DBusTestCase tests[] =
+{
+  { "cmutex_new", _dbus_check_cmutex_new},
+  { "cmutex_lock", _dbus_check_cmutex_lock},
+#ifdef DBUS_WIN
+  { "cmutex_lock_null_pointer", _dbus_check_cmutex_lock_null_pointer},
+  { "cmutex_double_lock", _dbus_check_cmutex_double_lock},
+  { "cmutex_unlock_null_pointer", _dbus_check_cmutex_unlock_null_pointer},
+  { "cmutex_null_free", _dbus_check_cmutex_null_free},
+  { "cmutex_double_free", _dbus_check_cmutex_double_free},
+#endif
+  { "rmutex_new", _dbus_check_rmutex_new},
+  { "rmutex_lock", _dbus_check_rmutex_lock},
+#ifdef DBUS_WIN
+  { "rmutex_lock_null_pointer", _dbus_check_rmutex_lock_null_pointer},
+#endif
+  { "rmutex_double_lock", _dbus_check_rmutex_double_lock},
+#ifdef DBUS_WIN
+  { "rmutex_unlock_null_pointer", _dbus_check_rmutex_unlock_null_pointer},
+  { "rmutex_null_free", _dbus_check_rmutex_null_free},
+  { "rmutex_double_free", _dbus_check_rmutex_double_free},
+#endif
+};
+
+int
+main (int    argc,
+      char **argv)
+{
+  dbus_setenv ("DBUS_FATAL_WARNINGS", "0");
+
+  return _dbus_test_main (argc, argv, _DBUS_N_ELEMENTS (tests), tests,
+                          DBUS_TEST_FLAGS_CHECK_MEMORY_LEAKS,
+                          NULL, NULL);
+}