2003-02-06 Anders Carlsson <andersca@codefactory.se>
authorAnders Carlsson <andersca@codefactory.se>
Wed, 5 Feb 2003 23:56:39 +0000 (23:56 +0000)
committerAnders Carlsson <andersca@codefactory.se>
Wed, 5 Feb 2003 23:56:39 +0000 (23:56 +0000)
* 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
dbus/Makefile.am
dbus/dbus-break-loader.c [deleted file]
test/Makefile.am
test/break-loader.c [new file with mode: 0644]

index 0c01740e2cf6cc2a2a04f6d80877de35d5954271..13d283fb535312468f7be8fa259b883700425052 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2003-02-06  Anders Carlsson  <andersca@codefactory.se>
+
+       * 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  <hp@pobox.com>
 
        * dbus/dbus-keyring.c, dbus/dbus-keyring.h: template files 
index c28b53834546f13befa312cbd8ff839683d163fc..f6f84a6116e585d674b1f4fe0809af7e41416035 100644 (file)
@@ -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 (file)
index c27299c..0000000
+++ /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 <sys/stat.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sys/wait.h>
-#include <string.h>
-
-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;
-}
index fc218b7cc2c0e0aa879c370f7cd76d1155869efd..972d67cfd6dfd6a25897fb25045568270814192c 100644 (file)
@@ -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 (file)
index 0000000..95ca808
--- /dev/null
@@ -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 <dbus/dbus.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/wait.h>
+#include <string.h>
+
+#define DBUS_COMPILATION 
+#include <dbus/dbus-string.h>
+#include <dbus/dbus-internals.h>
+#include <dbus/dbus-test.h>
+#include <dbus/dbus-marshal.h>
+#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;
+}