From e5631cfe85f125c572f598a414c0659d6ce72684 Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Wed, 5 Feb 2003 23:56:39 +0000 Subject: 2003-02-06 Anders Carlsson * dbus/Makefile.am: * dbus/dbus-break-loader.c: * test/Makefile.am: * test/break-loader.c: Move dbus-break-loader to test/ and rename it to break-loader. --- ChangeLog | 8 + dbus/Makefile.am | 2 +- dbus/dbus-break-loader.c | 592 ---------------------------------------------- test/Makefile.am | 6 +- test/break-loader.c | 595 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 609 insertions(+), 594 deletions(-) delete mode 100644 dbus/dbus-break-loader.c create mode 100644 test/break-loader.c diff --git a/ChangeLog b/ChangeLog index 0c01740e..13d283fb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2003-02-06 Anders Carlsson + + * dbus/Makefile.am: + * dbus/dbus-break-loader.c: + * test/Makefile.am: + * test/break-loader.c: + Move dbus-break-loader to test/ and rename it to break-loader. + 2003-02-02 Havoc Pennington * dbus/dbus-keyring.c, dbus/dbus-keyring.h: template files diff --git a/dbus/Makefile.am b/dbus/Makefile.am index c28b5383..f6f84a61 100644 --- a/dbus/Makefile.am +++ b/dbus/Makefile.am @@ -96,7 +96,7 @@ libdbus_1_la_LDFLAGS= -export-symbols-regex "^[^_].*" ## TESTS if DBUS_BUILD_TESTS TESTS_ENVIRONMENT=DBUS_TEST_DATA=$(top_srcdir)/test/data -TESTS=dbus-test dbus-break-loader +TESTS=dbus-test else TESTS= endif diff --git a/dbus/dbus-break-loader.c b/dbus/dbus-break-loader.c deleted file mode 100644 index c27299c9..00000000 --- a/dbus/dbus-break-loader.c +++ /dev/null @@ -1,592 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu" -*- */ -/* dbus-break-loader.c Program to find byte streams that break the message loader - * - * Copyright (C) 2003 Red Hat Inc. - * - * Licensed under the Academic Free License version 1.2 - * - * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include "dbus-types.h" -#include "dbus-test.h" -#include "dbus-internals.h" -#include "dbus-sysdeps.h" -#include "dbus-marshal.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static DBusString failure_dir; -static int total_attempts; -static int failures_this_iteration; - -static int -random_int_in_range (int start, - int end) -{ - /* such elegant math */ - double gap; - double v_double; - int v; - - if (start == end) - return start; - - _dbus_assert (end > start); - - gap = end - start - 1; /* -1 to not include "end" */ - v_double = ((double)start) + (((double)rand ())/RAND_MAX) * gap; - if (v_double < 0.0) - v = (v_double - 0.5); - else - v = (v_double + 0.5); - - if (v < start) - { - fprintf (stderr, "random_int_in_range() generated %d for range [%d,%d)\n", - v, start, end); - v = start; - } - else if (v >= end) - { - fprintf (stderr, "random_int_in_range() generated %d for range [%d,%d)\n", - v, start, end); - v = end - 1; - } - - /* printf (" %d of [%d,%d)\n", v, start, end); */ - - return v; -} - -static dbus_bool_t -try_mutated_data (const DBusString *data) -{ - int pid; - - total_attempts += 1; - /* printf (" attempt %d\n", total_attempts); */ - - pid = fork (); - - if (pid < 0) - { - fprintf (stderr, "fork() failed: %s\n", - strerror (errno)); - exit (1); - return FALSE; - } - - if (pid == 0) - { - /* Child, try loading the data */ - if (!dbus_internal_do_not_use_try_message_data (data, _DBUS_MESSAGE_UNKNOWN)) - exit (1); - else - exit (0); - } - else - { - /* Parent, wait for child */ - int status; - DBusString filename; - dbus_bool_t failed; - - if (waitpid (pid, &status, 0) < 0) - { - fprintf (stderr, "waitpid() failed: %s\n", strerror (errno)); - exit (1); - return FALSE; - } - - failed = FALSE; - - if (!_dbus_string_init (&filename, _DBUS_INT_MAX) || - !_dbus_string_copy (&failure_dir, 0, - &filename, 0) || - !_dbus_string_append_byte (&filename, '/')) - { - fprintf (stderr, "out of memory\n"); - exit (1); - } - - _dbus_string_append_int (&filename, total_attempts); - - if (WIFEXITED (status)) - { - if (WEXITSTATUS (status) != 0) - { - _dbus_string_append (&filename, "-exited-"); - _dbus_string_append_int (&filename, WEXITSTATUS (status)); - failed = TRUE; - } - } - else if (WIFSIGNALED (status)) - { - _dbus_string_append (&filename, "signaled-"); - _dbus_string_append_int (&filename, WTERMSIG (status)); - failed = TRUE; - } - - if (failed) - { - const char *filename_c; - DBusResultCode result; - - _dbus_string_append (&filename, ".message-raw"); - - _dbus_string_get_const_data (&filename, &filename_c); - printf ("Child failed, writing %s\n", - filename_c); - - result = _dbus_string_save_to_file (data, &filename); - - if (result != DBUS_RESULT_SUCCESS) - { - fprintf (stderr, "Failed to save failed message data: %s\n", - dbus_result_to_string (result)); - exit (1); /* so we can see the seed that was printed out */ - } - - failures_this_iteration += 1; - - return FALSE; - } - else - return TRUE; - } - - _dbus_assert_not_reached ("should not be reached"); - return TRUE; -} - -static void -randomly_shorten_or_lengthen (const DBusString *orig_data, - DBusString *mutated) -{ - int delta; - - if (orig_data != mutated) - { - _dbus_string_set_length (mutated, 0); - - if (!_dbus_string_copy (orig_data, 0, mutated, 0)) - _dbus_assert_not_reached ("out of mem"); - } - - if (_dbus_string_get_length (mutated) == 0) - delta = random_int_in_range (0, 10); - else - delta = random_int_in_range (- _dbus_string_get_length (mutated), - _dbus_string_get_length (mutated) * 3); - - if (delta < 0) - _dbus_string_shorten (mutated, - delta); - else if (delta > 0) - { - int i = 0; - - i = _dbus_string_get_length (mutated); - if (!_dbus_string_lengthen (mutated, delta)) - _dbus_assert_not_reached ("couldn't lengthen string"); - - while (i < _dbus_string_get_length (mutated)) - { - _dbus_string_set_byte (mutated, - i, - random_int_in_range (0, 256)); - ++i; - } - } -} - -static void -randomly_change_one_byte (const DBusString *orig_data, - DBusString *mutated) -{ - int i; - - if (orig_data != mutated) - { - _dbus_string_set_length (mutated, 0); - - if (!_dbus_string_copy (orig_data, 0, mutated, 0)) - _dbus_assert_not_reached ("out of mem"); - } - - if (_dbus_string_get_length (mutated) == 0) - return; - - i = random_int_in_range (0, _dbus_string_get_length (mutated)); - - _dbus_string_set_byte (mutated, i, - random_int_in_range (0, 256)); -} - -static void -randomly_remove_one_byte (const DBusString *orig_data, - DBusString *mutated) -{ - int i; - - if (orig_data != mutated) - { - _dbus_string_set_length (mutated, 0); - - if (!_dbus_string_copy (orig_data, 0, mutated, 0)) - _dbus_assert_not_reached ("out of mem"); - } - - if (_dbus_string_get_length (mutated) == 0) - return; - - i = random_int_in_range (0, _dbus_string_get_length (mutated)); - - _dbus_string_delete (mutated, i, 1); -} - - -static void -randomly_add_one_byte (const DBusString *orig_data, - DBusString *mutated) -{ - int i; - - if (orig_data != mutated) - { - _dbus_string_set_length (mutated, 0); - - if (!_dbus_string_copy (orig_data, 0, mutated, 0)) - _dbus_assert_not_reached ("out of mem"); - } - - i = random_int_in_range (0, _dbus_string_get_length (mutated)); - - _dbus_string_insert_byte (mutated, i, - random_int_in_range (0, 256)); -} - -static void -randomly_modify_length (const DBusString *orig_data, - DBusString *mutated) -{ - int i; - int byte_order; - const char *d; - dbus_uint32_t orig; - int delta; - - if (orig_data != mutated) - { - _dbus_string_set_length (mutated, 0); - - if (!_dbus_string_copy (orig_data, 0, mutated, 0)) - _dbus_assert_not_reached ("out of mem"); - } - - if (_dbus_string_get_length (mutated) < 12) - return; - - _dbus_string_get_const_data (mutated, &d); - - if (!(*d == DBUS_LITTLE_ENDIAN || - *d == DBUS_BIG_ENDIAN)) - return; - - byte_order = *d; - - i = random_int_in_range (4, _dbus_string_get_length (mutated) - 8); - i = _DBUS_ALIGN_VALUE (i, 4); - - orig = _dbus_demarshal_uint32 (mutated, byte_order, i, NULL); - - delta = random_int_in_range (-10, 10); - - _dbus_marshal_set_uint32 (mutated, byte_order, i, - (unsigned) (orig + delta)); -} - -static void -randomly_do_n_things (const DBusString *orig_data, - DBusString *mutated, - int n) -{ - int i; - void (* functions[]) (const DBusString *orig_data, - DBusString *mutated) = - { - randomly_shorten_or_lengthen, - randomly_change_one_byte, - randomly_add_one_byte, - randomly_remove_one_byte, - randomly_modify_length - }; - - _dbus_string_set_length (mutated, 0); - - if (!_dbus_string_copy (orig_data, 0, mutated, 0)) - _dbus_assert_not_reached ("out of mem"); - - i = 0; - while (i < n) - { - int which; - - which = random_int_in_range (0, _DBUS_N_ELEMENTS (functions)); - - (* functions[which]) (mutated, mutated); - - ++i; - } -} - -static dbus_bool_t -find_breaks_based_on (const DBusString *filename, - dbus_bool_t is_raw, - DBusMessageValidity expected_validity, - void *data) -{ - DBusString orig_data; - DBusString mutated; - const char *filename_c; - dbus_bool_t retval; - int i; - - _dbus_string_get_const_data (filename, &filename_c); - - retval = FALSE; - - if (!_dbus_string_init (&orig_data, _DBUS_INT_MAX)) - _dbus_assert_not_reached ("could not allocate string\n"); - - if (!_dbus_string_init (&mutated, _DBUS_INT_MAX)) - _dbus_assert_not_reached ("could not allocate string\n"); - - if (!dbus_internal_do_not_use_load_message_file (filename, is_raw, - &orig_data)) - { - fprintf (stderr, "could not load file %s\n", filename_c); - goto failed; - } - - i = 0; - while (i < 100) - { - randomly_change_one_byte (&orig_data, &mutated); - try_mutated_data (&mutated); - - ++i; - } - - i = 0; - while (i < 50) - { - randomly_modify_length (&orig_data, &mutated); - try_mutated_data (&mutated); - - ++i; - } - - i = 0; - while (i < 50) - { - randomly_remove_one_byte (&orig_data, &mutated); - try_mutated_data (&mutated); - - ++i; - } - - i = 0; - while (i < 50) - { - randomly_add_one_byte (&orig_data, &mutated); - try_mutated_data (&mutated); - - ++i; - } - - i = 0; - while (i < 15) - { - randomly_shorten_or_lengthen (&orig_data, &mutated); - try_mutated_data (&mutated); - - ++i; - } - - i = 0; - while (i < 42) - { - randomly_do_n_things (&orig_data, &mutated, 2); - try_mutated_data (&mutated); - - ++i; - } - - i = 0; - while (i < 42) - { - randomly_do_n_things (&orig_data, &mutated, 3); - try_mutated_data (&mutated); - - ++i; - } - - i = 0; - while (i < 42) - { - randomly_do_n_things (&orig_data, &mutated, 4); - try_mutated_data (&mutated); - - ++i; - } - - retval = TRUE; - - failed: - - _dbus_string_free (&orig_data); - _dbus_string_free (&mutated); - - /* FALSE means end the whole process */ - return retval; -} - -static unsigned int -get_random_seed (void) -{ - DBusString bytes; - unsigned int seed; - int fd; - const char *s; - - seed = 0; - - if (!_dbus_string_init (&bytes, _DBUS_INT_MAX)) - exit (1); - - fd = open ("/dev/urandom", O_RDONLY); - if (fd < 0) - goto use_fallback; - - if (_dbus_read (fd, &bytes, 4) != 4) - goto use_fallback; - - close (fd); - - _dbus_string_get_const_data (&bytes, &s); - - seed = * (unsigned int*) s; - goto out; - - use_fallback: - { - long tv_usec; - - fprintf (stderr, "could not open/read /dev/urandom, using current time for seed\n"); - - _dbus_get_current_time (NULL, &tv_usec); - - seed = tv_usec; - } - - out: - _dbus_string_free (&bytes); - - return seed; -} - -int -main (int argc, - char **argv) -{ - const char *test_data_dir; - const char *failure_dir_c; - int total_failures_found; - - if (argc > 1) - test_data_dir = argv[1]; - else - { - fprintf (stderr, "Must specify a top_srcdir/test/data directory\n"); - return 1; - } - - total_failures_found = 0; - total_attempts = 0; - - if (!_dbus_string_init (&failure_dir, _DBUS_INT_MAX)) - return 1; - - /* so you can leave it overnight safely */ -#define MAX_FAILURES 1000 - - while (total_failures_found < MAX_FAILURES) - { - unsigned int seed; - - failures_this_iteration = 0; - - seed = get_random_seed (); - - _dbus_string_set_length (&failure_dir, 0); - - if (!_dbus_string_append (&failure_dir, "failures-")) - return 1; - - if (!_dbus_string_append_uint (&failure_dir, seed)) - return 1; - - _dbus_string_get_const_data (&failure_dir, &failure_dir_c); - - if (mkdir (failure_dir_c, 0700) < 0) - { - if (errno != EEXIST) - fprintf (stderr, "didn't mkdir %s: %s\n", - failure_dir_c, strerror (errno)); - } - - printf ("next seed = %u \ttotal failures %d of %d attempts\n", - seed, total_failures_found, total_attempts); - - srand (seed); - - if (!dbus_internal_do_not_use_foreach_message_file (test_data_dir, - find_breaks_based_on, - NULL)) - { - fprintf (stderr, "fatal error iterating over message files\n"); - rmdir (failure_dir_c); - return 1; - } - - printf ("Found %d failures with seed %u stored in %s\n", - failures_this_iteration, seed, failure_dir_c); - - total_failures_found += failures_this_iteration; - - rmdir (failure_dir_c); /* does nothing if non-empty */ - } - - return 0; -} diff --git a/test/Makefile.am b/test/Makefile.am index fc218b7c..972d67cf 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -2,7 +2,7 @@ INCLUDES=-I$(top_srcdir) $(DBUS_TEST_CFLAGS) if DBUS_BUILD_TESTS -TEST_BINARIES=echo-client echo-server unbase64 bus-test +TEST_BINARIES=echo-client echo-server unbase64 bus-test break-loader else TEST_BINARIES= endif @@ -26,11 +26,15 @@ unbase64_SOURCES= \ bus_test_SOURCES = \ bus-test.c +break_loader_SOURCES= \ + break-loader.c + TEST_LIBS=$(DBUS_TEST_LIBS) $(top_builddir)/dbus/libdbus-convenience.la $(top_builddir)/dbus/libdbus-1.la echo_client_LDADD=$(TEST_LIBS) echo_server_LDADD=$(TEST_LIBS) unbase64_LDADD=$(TEST_LIBS) +break_loader_LDADD= $(TEST_LIBS) bus_test_LDADD=$(TEST_LIBS) $(top_builddir)/bus/libdbus-daemon.la dist-hook: diff --git a/test/break-loader.c b/test/break-loader.c new file mode 100644 index 00000000..95ca808e --- /dev/null +++ b/test/break-loader.c @@ -0,0 +1,595 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-break-loader.c Program to find byte streams that break the message loader + * + * Copyright (C) 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DBUS_COMPILATION +#include +#include +#include +#include +#undef DBUS_COMPILATION + +static DBusString failure_dir; +static int total_attempts; +static int failures_this_iteration; + +static int +random_int_in_range (int start, + int end) +{ + /* such elegant math */ + double gap; + double v_double; + int v; + + if (start == end) + return start; + + _dbus_assert (end > start); + + gap = end - start - 1; /* -1 to not include "end" */ + v_double = ((double)start) + (((double)rand ())/RAND_MAX) * gap; + if (v_double < 0.0) + v = (v_double - 0.5); + else + v = (v_double + 0.5); + + if (v < start) + { + fprintf (stderr, "random_int_in_range() generated %d for range [%d,%d)\n", + v, start, end); + v = start; + } + else if (v >= end) + { + fprintf (stderr, "random_int_in_range() generated %d for range [%d,%d)\n", + v, start, end); + v = end - 1; + } + + /* printf (" %d of [%d,%d)\n", v, start, end); */ + + return v; +} + +static dbus_bool_t +try_mutated_data (const DBusString *data) +{ + int pid; + + total_attempts += 1; + /* printf (" attempt %d\n", total_attempts); */ + + pid = fork (); + + if (pid < 0) + { + fprintf (stderr, "fork() failed: %s\n", + strerror (errno)); + exit (1); + return FALSE; + } + + if (pid == 0) + { + /* Child, try loading the data */ + if (!dbus_internal_do_not_use_try_message_data (data, _DBUS_MESSAGE_UNKNOWN)) + exit (1); + else + exit (0); + } + else + { + /* Parent, wait for child */ + int status; + DBusString filename; + dbus_bool_t failed; + + if (waitpid (pid, &status, 0) < 0) + { + fprintf (stderr, "waitpid() failed: %s\n", strerror (errno)); + exit (1); + return FALSE; + } + + failed = FALSE; + + if (!_dbus_string_init (&filename, _DBUS_INT_MAX) || + !_dbus_string_copy (&failure_dir, 0, + &filename, 0) || + !_dbus_string_append_byte (&filename, '/')) + { + fprintf (stderr, "out of memory\n"); + exit (1); + } + + _dbus_string_append_int (&filename, total_attempts); + + if (WIFEXITED (status)) + { + if (WEXITSTATUS (status) != 0) + { + _dbus_string_append (&filename, "-exited-"); + _dbus_string_append_int (&filename, WEXITSTATUS (status)); + failed = TRUE; + } + } + else if (WIFSIGNALED (status)) + { + _dbus_string_append (&filename, "signaled-"); + _dbus_string_append_int (&filename, WTERMSIG (status)); + failed = TRUE; + } + + if (failed) + { + const char *filename_c; + DBusResultCode result; + + _dbus_string_append (&filename, ".message-raw"); + + _dbus_string_get_const_data (&filename, &filename_c); + printf ("Child failed, writing %s\n", + filename_c); + + result = _dbus_string_save_to_file (data, &filename); + + if (result != DBUS_RESULT_SUCCESS) + { + fprintf (stderr, "Failed to save failed message data: %s\n", + dbus_result_to_string (result)); + exit (1); /* so we can see the seed that was printed out */ + } + + failures_this_iteration += 1; + + return FALSE; + } + else + return TRUE; + } + + _dbus_assert_not_reached ("should not be reached"); + return TRUE; +} + +static void +randomly_shorten_or_lengthen (const DBusString *orig_data, + DBusString *mutated) +{ + int delta; + + if (orig_data != mutated) + { + _dbus_string_set_length (mutated, 0); + + if (!_dbus_string_copy (orig_data, 0, mutated, 0)) + _dbus_assert_not_reached ("out of mem"); + } + + if (_dbus_string_get_length (mutated) == 0) + delta = random_int_in_range (0, 10); + else + delta = random_int_in_range (- _dbus_string_get_length (mutated), + _dbus_string_get_length (mutated) * 3); + + if (delta < 0) + _dbus_string_shorten (mutated, - delta); + else if (delta > 0) + { + int i = 0; + + i = _dbus_string_get_length (mutated); + if (!_dbus_string_lengthen (mutated, delta)) + _dbus_assert_not_reached ("couldn't lengthen string"); + + while (i < _dbus_string_get_length (mutated)) + { + _dbus_string_set_byte (mutated, + i, + random_int_in_range (0, 256)); + ++i; + } + } +} + +static void +randomly_change_one_byte (const DBusString *orig_data, + DBusString *mutated) +{ + int i; + + if (orig_data != mutated) + { + _dbus_string_set_length (mutated, 0); + + if (!_dbus_string_copy (orig_data, 0, mutated, 0)) + _dbus_assert_not_reached ("out of mem"); + } + + if (_dbus_string_get_length (mutated) == 0) + return; + + i = random_int_in_range (0, _dbus_string_get_length (mutated)); + + _dbus_string_set_byte (mutated, i, + random_int_in_range (0, 256)); +} + +static void +randomly_remove_one_byte (const DBusString *orig_data, + DBusString *mutated) +{ + int i; + + if (orig_data != mutated) + { + _dbus_string_set_length (mutated, 0); + + if (!_dbus_string_copy (orig_data, 0, mutated, 0)) + _dbus_assert_not_reached ("out of mem"); + } + + if (_dbus_string_get_length (mutated) == 0) + return; + + i = random_int_in_range (0, _dbus_string_get_length (mutated)); + + _dbus_string_delete (mutated, i, 1); +} + + +static void +randomly_add_one_byte (const DBusString *orig_data, + DBusString *mutated) +{ + int i; + + if (orig_data != mutated) + { + _dbus_string_set_length (mutated, 0); + + if (!_dbus_string_copy (orig_data, 0, mutated, 0)) + _dbus_assert_not_reached ("out of mem"); + } + + i = random_int_in_range (0, _dbus_string_get_length (mutated)); + + _dbus_string_insert_byte (mutated, i, + random_int_in_range (0, 256)); +} + +static void +randomly_modify_length (const DBusString *orig_data, + DBusString *mutated) +{ + int i; + int byte_order; + const char *d; + dbus_uint32_t orig; + int delta; + + if (orig_data != mutated) + { + _dbus_string_set_length (mutated, 0); + + if (!_dbus_string_copy (orig_data, 0, mutated, 0)) + _dbus_assert_not_reached ("out of mem"); + } + + if (_dbus_string_get_length (mutated) < 12) + return; + + _dbus_string_get_const_data (mutated, &d); + + if (!(*d == DBUS_LITTLE_ENDIAN || + *d == DBUS_BIG_ENDIAN)) + return; + + byte_order = *d; + + i = random_int_in_range (4, _dbus_string_get_length (mutated) - 8); + i = _DBUS_ALIGN_VALUE (i, 4); + + orig = _dbus_demarshal_uint32 (mutated, byte_order, i, NULL); + + delta = random_int_in_range (-10, 10); + + _dbus_marshal_set_uint32 (mutated, byte_order, i, + (unsigned) (orig + delta)); +} + +static void +randomly_do_n_things (const DBusString *orig_data, + DBusString *mutated, + int n) +{ + int i; + void (* functions[]) (const DBusString *orig_data, + DBusString *mutated) = + { + randomly_shorten_or_lengthen, + randomly_change_one_byte, + randomly_add_one_byte, + randomly_remove_one_byte, + randomly_modify_length + }; + + _dbus_string_set_length (mutated, 0); + + if (!_dbus_string_copy (orig_data, 0, mutated, 0)) + _dbus_assert_not_reached ("out of mem"); + + i = 0; + while (i < n) + { + int which; + + which = random_int_in_range (0, _DBUS_N_ELEMENTS (functions)); + + (* functions[which]) (mutated, mutated); + + ++i; + } +} + +static dbus_bool_t +find_breaks_based_on (const DBusString *filename, + dbus_bool_t is_raw, + DBusMessageValidity expected_validity, + void *data) +{ + DBusString orig_data; + DBusString mutated; + const char *filename_c; + dbus_bool_t retval; + int i; + + _dbus_string_get_const_data (filename, &filename_c); + + retval = FALSE; + + if (!_dbus_string_init (&orig_data, _DBUS_INT_MAX)) + _dbus_assert_not_reached ("could not allocate string\n"); + + if (!_dbus_string_init (&mutated, _DBUS_INT_MAX)) + _dbus_assert_not_reached ("could not allocate string\n"); + + if (!dbus_internal_do_not_use_load_message_file (filename, is_raw, + &orig_data)) + { + fprintf (stderr, "could not load file %s\n", filename_c); + goto failed; + } + + i = 0; + while (i < 100) + { + randomly_change_one_byte (&orig_data, &mutated); + try_mutated_data (&mutated); + + ++i; + } + + i = 0; + while (i < 50) + { + randomly_modify_length (&orig_data, &mutated); + try_mutated_data (&mutated); + + ++i; + } + + i = 0; + while (i < 50) + { + randomly_remove_one_byte (&orig_data, &mutated); + try_mutated_data (&mutated); + + ++i; + } + + i = 0; + while (i < 50) + { + randomly_add_one_byte (&orig_data, &mutated); + try_mutated_data (&mutated); + + ++i; + } + + i = 0; + while (i < 15) + { + randomly_shorten_or_lengthen (&orig_data, &mutated); + try_mutated_data (&mutated); + + ++i; + } + + i = 0; + while (i < 42) + { + randomly_do_n_things (&orig_data, &mutated, 2); + try_mutated_data (&mutated); + + ++i; + } + + i = 0; + while (i < 42) + { + randomly_do_n_things (&orig_data, &mutated, 3); + try_mutated_data (&mutated); + + ++i; + } + + i = 0; + while (i < 42) + { + randomly_do_n_things (&orig_data, &mutated, 4); + try_mutated_data (&mutated); + + ++i; + } + + retval = TRUE; + + failed: + + _dbus_string_free (&orig_data); + _dbus_string_free (&mutated); + + /* FALSE means end the whole process */ + return retval; +} + +static unsigned int +get_random_seed (void) +{ + DBusString bytes; + unsigned int seed; + int fd; + const char *s; + + seed = 0; + + if (!_dbus_string_init (&bytes, _DBUS_INT_MAX)) + exit (1); + + fd = open ("/dev/urandom", O_RDONLY); + if (fd < 0) + goto use_fallback; + + if (_dbus_read (fd, &bytes, 4) != 4) + goto use_fallback; + + close (fd); + + _dbus_string_get_const_data (&bytes, &s); + + seed = * (unsigned int*) s; + goto out; + + use_fallback: + { + long tv_usec; + + fprintf (stderr, "could not open/read /dev/urandom, using current time for seed\n"); + + _dbus_get_current_time (NULL, &tv_usec); + + seed = tv_usec; + } + + out: + _dbus_string_free (&bytes); + + return seed; +} + +int +main (int argc, + char **argv) +{ + const char *test_data_dir; + const char *failure_dir_c; + int total_failures_found; + + if (argc > 1) + test_data_dir = argv[1]; + else + { + fprintf (stderr, "Must specify a top_srcdir/test/data directory\n"); + return 1; + } + + total_failures_found = 0; + total_attempts = 0; + + if (!_dbus_string_init (&failure_dir, _DBUS_INT_MAX)) + return 1; + + /* so you can leave it overnight safely */ +#define MAX_FAILURES 1000 + + while (total_failures_found < MAX_FAILURES) + { + unsigned int seed; + + failures_this_iteration = 0; + + seed = get_random_seed (); + + _dbus_string_set_length (&failure_dir, 0); + + if (!_dbus_string_append (&failure_dir, "failures-")) + return 1; + + if (!_dbus_string_append_uint (&failure_dir, seed)) + return 1; + + _dbus_string_get_const_data (&failure_dir, &failure_dir_c); + + if (mkdir (failure_dir_c, 0700) < 0) + { + if (errno != EEXIST) + fprintf (stderr, "didn't mkdir %s: %s\n", + failure_dir_c, strerror (errno)); + } + + printf ("next seed = %u \ttotal failures %d of %d attempts\n", + seed, total_failures_found, total_attempts); + + srand (seed); + + if (!dbus_internal_do_not_use_foreach_message_file (test_data_dir, + find_breaks_based_on, + NULL)) + { + fprintf (stderr, "fatal error iterating over message files\n"); + rmdir (failure_dir_c); + return 1; + } + + printf ("Found %d failures with seed %u stored in %s\n", + failures_this_iteration, seed, failure_dir_c); + + total_failures_found += failures_this_iteration; + + rmdir (failure_dir_c); /* does nothing if non-empty */ + } + + return 0; +} -- cgit