From a0c3c3686102e5f96f400f4a3e4e46cba0d1c7a8 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Wed, 28 Sep 2011 17:35:42 +0100 Subject: [PATCH 09/10] Add a manual test for various invalid behaviour Most of this has been sitting in a branch since fd.o #30171; fixing fd.o #40151, another case of library-user error leading to undefined behaviour and a hard-to-diagnose crash, seems a good time to get this merged. Signed-off-by: Simon McVittie Bug: https://bugs.freedesktop.org/show_bug.cgi?id=40151 --- .gitignore | 1 + configure.ac | 1 + test/Makefile.am | 4 +- test/manual/Makefile.am | 27 ++++ test/manual/invalid-usage.c | 295 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 326 insertions(+), 2 deletions(-) create mode 100644 test/manual/Makefile.am create mode 100644 test/manual/invalid-usage.c diff --git a/.gitignore b/.gitignore index ac454ed..6057c00 100644 --- a/.gitignore +++ b/.gitignore @@ -223,3 +223,4 @@ tools/dbus-glib-bindings.h /test/interfaces/test-server /test/interfaces/test-service /test/interfaces/test-client +/test/manual/test-invalid-usage diff --git a/configure.ac b/configure.ac index d70b9f7..9c99029 100644 --- a/configure.ac +++ b/configure.ac @@ -450,6 +450,7 @@ test/interfaces/Makefile test/data/valid-service-files/debug-glib.service test/data/valid-service-files/debug-echo.service test/data/valid-service-files/interfaces-test.service +test/manual/Makefile tools/Makefile dbus-glib-1.pc dbus-glib-1-uninstalled.pc diff --git a/test/Makefile.am b/test/Makefile.am index 7ba11a8..e0531f6 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,5 +1,5 @@ -SUBDIRS = . core interfaces -DIST_SUBDIRS = core interfaces +SUBDIRS = . core interfaces manual +DIST_SUBDIRS = core interfaces manual INCLUDES = \ -I$(top_srcdir) \ diff --git a/test/manual/Makefile.am b/test/manual/Makefile.am new file mode 100644 index 0000000..5a8dfd1 --- /dev/null +++ b/test/manual/Makefile.am @@ -0,0 +1,27 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir) \ + -I$(top_builddir) \ + -I$(top_srcdir)/test/core \ + -I$(top_builddir)/test/core \ + $(DBUS_CFLAGS) \ + $(DBUS_GLIB_CFLAGS) \ + $(NULL) + +LDADD = \ + $(top_builddir)/dbus/libdbus-glib-1.la \ + $(DBUS_LIBS) \ + $(DBUS_GLIB_LIBS) \ + $(NULL) + +noinst_PROGRAMS = \ + test-invalid-usage \ + $(NULL) + +# This "test" exercises invalid usage. It is deliberately not run in +# TESTS, because it's (by design) full of bugs. +test_invalid_usage_SOURCES = \ + ../core/my-object-marshal.c \ + ../core/my-object-marshal.h \ + ../core/my-object.c \ + ../core/my-object.h \ + invalid-usage.c diff --git a/test/manual/invalid-usage.c b/test/manual/invalid-usage.c new file mode 100644 index 0000000..59a8314 --- /dev/null +++ b/test/manual/invalid-usage.c @@ -0,0 +1,295 @@ +/* Manual test for various invalid usages which should not crash us (in order + * to be nice to fallible programmers), unless checks have been disabled (in + * which case, you asked for it, you got it). + * + * Copyright © 2006-2010 Red Hat, Inc. + * Copyright © 2006-2010 Collabora Ltd. + * Copyright © 2006-2011 Nokia Corporation + * Copyright © 2006 Steve Frécinaux + * + * 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 + +#include + +#include +#include +#include + +#include + +#include "my-object.h" +#include "test-service-glib-bindings.h" + +/* my-object wants this to exist */ +GMainLoop *loop = NULL; + +typedef struct { + GError *error; + DBusGConnection *conn; + DBusGProxy *proxy; + DBusGProxy *proxy_for_self; + GObject *object; +} Fixture; + +static void +setup (Fixture *f, + gconstpointer context) +{ + /* this test is all about (mostly critical) warnings, so don't crash out on + * programming errors */ + g_setenv ("DBUS_FATAL_WARNINGS", "0", TRUE); + g_log_set_always_fatal (G_LOG_LEVEL_ERROR); + + dbus_g_type_specialized_init (); + + /* This is a bug: you're not meant to register any domain more than + * once. It shouldn't crash, though. */ + dbus_g_error_domain_register (MY_OBJECT_ERROR, NULL, MY_TYPE_ERROR); + + f->conn = dbus_g_bus_get_private (DBUS_BUS_SESSION, NULL, &f->error); + g_assert_no_error (f->error); + g_assert (f->conn != NULL); + + f->proxy = dbus_g_proxy_new_for_name (f->conn, "com.example.Test", + "/com/example/Test/Object", "com.example.Test.Fallible"); + g_assert (f->proxy != NULL); + + f->object = g_object_new (MY_TYPE_OBJECT, NULL); + g_assert (MY_IS_OBJECT (f->object)); + dbus_g_connection_register_g_object (f->conn, "/com/example/Test/Object", + f->object); + + f->proxy_for_self = dbus_g_proxy_new_for_name (f->conn, + dbus_bus_get_unique_name (dbus_g_connection_get_connection (f->conn)), + "/com/example/Test/Object", "org.freedesktop.DBus.GLib.Tests.MyObject"); + g_assert (f->proxy_for_self != NULL); +} + +static void +test_invalid_gtype (Fixture *f, + gconstpointer context) +{ + /* G_TYPE_GTYPE is not handled by the dbus-glib type system (and would make + * no sense anyway) */ + dbus_g_proxy_call_no_reply (f->proxy, "Fail", + G_TYPE_GTYPE, G_TYPE_STRING, + G_TYPE_INVALID); +} + +static void +test_invalid_utf8 (Fixture *f, + gconstpointer context) +{ + g_test_bug ("30171"); + + /* This provokes a libdbus warning, which is fatal-by-default */ + dbus_g_proxy_call_no_reply (f->proxy, "Fail", + G_TYPE_STRING, "\xfe\xfe\xfe", + G_TYPE_INVALID); +} + +static void +test_invalid_bool (Fixture *f, + gconstpointer context) +{ + g_test_bug ("30171"); + + /* This provokes a libdbus warning, which is fatal-by-default */ + dbus_g_proxy_call_no_reply (f->proxy, "Fail", + G_TYPE_BOOLEAN, (gboolean) (-42), + G_TYPE_INVALID); +} + +static void +test_invalid_path (Fixture *f, + gconstpointer context) +{ + g_test_bug ("30171"); + + /* This provokes a libdbus warning, which is fatal-by-default */ + dbus_g_proxy_call_no_reply (f->proxy, "Fail", + DBUS_TYPE_G_OBJECT_PATH, "$%#*!", + G_TYPE_INVALID); +} + +static void +test_invalid_utf8s (Fixture *f, + gconstpointer context) +{ + gchar *bad_strings[] = { "\xfe\xfe\xfe", NULL }; + GStrv bad_strv = bad_strings; + + g_test_bug ("30171"); + + /* This provokes a libdbus warning, which is fatal-by-default */ + dbus_g_proxy_call_no_reply (f->proxy, "Fail", + G_TYPE_STRV, bad_strv, + G_TYPE_INVALID); +} + +static void +test_invalid_bools (Fixture *f, + gconstpointer context) +{ + GArray *array; + gboolean maybe = (gboolean) (-23); + + g_test_bug ("30171"); + + array = g_array_new (FALSE, FALSE, sizeof (gboolean)); + + g_array_append_val (array, maybe); + + /* This provokes a libdbus warning, which is fatal-by-default */ + dbus_g_proxy_call_no_reply (f->proxy, "Fail", + dbus_g_type_get_collection ("GArray", G_TYPE_BOOLEAN), array, + G_TYPE_INVALID); + + g_array_free (array, TRUE); +} + +static void +test_invalid_paths (Fixture *f, + gconstpointer context) +{ + GPtrArray *array; + + g_test_bug ("30171"); + + array = g_ptr_array_new (); + g_ptr_array_add (array, "bees"); + + /* This provokes a libdbus warning, which is fatal-by-default */ + dbus_g_proxy_call_no_reply (f->proxy, "Fail", + dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH), array, + G_TYPE_INVALID); + + g_ptr_array_free (array, TRUE); +} + +static void +throw_error_cb (DBusGProxy *proxy, + GError *error, + gpointer user_data) +{ + GError **error_out = user_data; + + g_assert (error != NULL); + *error_out = g_error_copy (error); +} + +static void +test_error_out_of_range (Fixture *f, + gconstpointer context) +{ + GError *error = NULL; + + g_test_bug ("40151"); + + /* This is a bug: -1 isn't a valid code for the domain. */ + my_object_save_error ((MyObject *) f->object, MY_OBJECT_ERROR, -1, + "stop being so negative"); + + if (!org_freedesktop_DBus_GLib_Tests_MyObject_throw_error_async ( + f->proxy_for_self, throw_error_cb, &error)) + g_error ("Failed to start async ThrowError call"); + + while (error == NULL) + g_main_context_iteration (NULL, TRUE); + + g_assert_error (error, DBUS_GERROR, DBUS_GERROR_REMOTE_EXCEPTION); + g_clear_error (&error); + + /* This is a bug: 666 isn't a valid code for the domain. */ + my_object_save_error ((MyObject *) f->object, MY_OBJECT_ERROR, 666, + "demonic possession detected"); + + if (!org_freedesktop_DBus_GLib_Tests_MyObject_throw_error_async ( + f->proxy_for_self, throw_error_cb, &error)) + g_error ("Failed to start async ThrowError call"); + + while (error == NULL) + g_main_context_iteration (NULL, TRUE); + + g_assert_error (error, DBUS_GERROR, DBUS_GERROR_REMOTE_EXCEPTION); + g_clear_error (&error); +} + +static void +teardown (Fixture *f, + gconstpointer context G_GNUC_UNUSED) +{ + g_clear_error (&f->error); + + if (f->proxy != NULL) + { + g_object_unref (f->proxy); + f->proxy = NULL; + } + + if (f->object != NULL) + { + g_object_unref (f->object); + f->object = NULL; + } + + if (f->proxy_for_self != NULL) + { + g_object_unref (f->proxy_for_self); + f->proxy_for_self = NULL; + } + + if (f->conn != NULL) + { + dbus_connection_close (dbus_g_connection_get_connection (f->conn)); + dbus_g_connection_unref (f->conn); + f->conn = NULL; + } +} + +int +main (int argc, + char **argv) +{ + g_test_init (&argc, &argv, NULL); + g_test_bug_base ("https://bugs.freedesktop.org/show_bug.cgi?id="); + + g_type_init (); + + g_test_add ("/invalid/gtype", Fixture, NULL, setup, test_invalid_gtype, + teardown); + g_test_add ("/invalid/utf8", Fixture, NULL, setup, test_invalid_utf8, + teardown); + g_test_add ("/invalid/bool", Fixture, NULL, setup, test_invalid_bool, + teardown); + g_test_add ("/invalid/path", Fixture, NULL, setup, test_invalid_path, + teardown); + g_test_add ("/invalid/utf8s", Fixture, NULL, setup, test_invalid_utf8s, + teardown); + g_test_add ("/invalid/bools", Fixture, NULL, setup, test_invalid_bools, + teardown); + g_test_add ("/invalid/paths", Fixture, NULL, setup, test_invalid_paths, + teardown); + g_test_add ("/invalid/error/out-of-range", Fixture, NULL, setup, + test_error_out_of_range, teardown); + + return g_test_run (); +} -- 1.7.6.3