diff mbox

Demangler fuzzer

Message ID 20140812090240.GA15234@blade.nx
State New
Headers show

Commit Message

Gary Benson Aug. 12, 2014, 9:02 a.m. UTC
Jakub Jelinek wrote:
> On Mon, Aug 11, 2014 at 05:04:20PM +0100, Gary Benson wrote:
> > +	case 's':
> > +	  seed = atoi (optarg);
> > +	  break;
> > +
> > +	case 't':
> > +	  timeout = atoi (optarg);
> > +	  break;
> > +
> > +	case 'm':
> > +	  maxcount = atoi (optarg);
> > +	  break;
> > +	}
> > +    }
> > +  while (optchr != -1);
> > +
> > +  if (seed == -1)
> > +    seed = time (NULL);
> > +  srand (seed);
> > +  printf ("%s: seed = %d\n", program_name, seed);
> 
> That will still make it non-reproduceable if time returns -1
> (well, as you cast time_t to int, that can be e.g. on 64-bit arches
> any time which has 0xffffffff in the low 32 bits).  So perhaps do
>   if (seed == -1)
>     {
>       seed = time (NULL);
>       if (seed == -1) seed = 0;
>     }
> or something similar?

I've added a flag, seed_set, so seed will only be set to time (NULL)
if the user has not specified a seed on the command line.

> > +  if (timeout != -1)
> > +    {
> > +      signal (SIGALRM, alarm_handler);
> > +      alarm (timeout);
> > +    }
> 

> Not sure how much portable signal/alarm is.  So probably should be
> guarded by the existence of signal.h, SIGALRM being defined etc.

I've removed the timeout code.  Users can limit the run by setting a
maximum number of iterations.  That's more consistent for testing
anyway: 5000000 iterations is 5000000 iterations wherever you run it.

How about this one?

Thanks,
Gary

Comments

Jakub Jelinek Aug. 12, 2014, 9:07 a.m. UTC | #1
On Tue, Aug 12, 2014 at 10:02:40AM +0100, Gary Benson wrote:
> I've removed the timeout code.  Users can limit the run by setting a
> maximum number of iterations.  That's more consistent for testing
> anyway: 5000000 iterations is 5000000 iterations wherever you run it.
> 
> How about this one?

LGTM, but I think it would be best to hear from Ian on this too.

Perhaps MAXLEN could be a command line option (then you'd need to allocate
the buffer dynamically?), but not sure if it is worth it.

	Jakub
Gary Benson Aug. 12, 2014, 9:33 a.m. UTC | #2
Jakub Jelinek wrote:
> On Tue, Aug 12, 2014 at 10:02:40AM +0100, Gary Benson wrote:
> > I've removed the timeout code.  Users can limit the run by setting a
> > maximum number of iterations.  That's more consistent for testing
> > anyway: 5000000 iterations is 5000000 iterations wherever you run it.
> > 
> > How about this one?
> 
> LGTM, but I think it would be best to hear from Ian on this too.

Cool, I'll wait for Ian's reply.

> Perhaps MAXLEN could be a command line option (then you'd need to
> allocate the buffer dynamically?), but not sure if it is worth it.

Right now it generally crashes after a few hundred thousand iterations
(usually under five seconds).  It might be worth extending the fuzzer
once the bugs are fixed such that it runs without crashing for longer.
(I'll likely fix some of them myself in gaps between projects).

Cheers,
Gary
Ian Lance Taylor Aug. 12, 2014, 1:44 p.m. UTC | #3
On Tue, Aug 12, 2014 at 2:02 AM, Gary Benson <gbenson@redhat.com> wrote:

> +#include <demangle.h>

Include demangle.h with "".

> +int
> +main (int argc, char *argv[])
> +{
> +  char symbol[2 + MAXLEN + 1] = "_Z";
> +  int seed = -1, seed_set = 0;
> +  int count = 0, maxcount = -1;

I think that by default the program should stop.  That will make it
possible to eventually run as part of "make check".  Give it some
number of iterations that stops it in a second or so.  You can still
have it run forever by using -m -1.

This is OK with those changes.

Thanks.

Ian
Gary Benson Aug. 12, 2014, 5:11 p.m. UTC | #4
Ian Lance Taylor wrote:
> On Tue, Aug 12, 2014 at 2:02 AM, Gary Benson <gbenson@redhat.com> wrote:
> > +#include <demangle.h>
> 
> Include demangle.h with "".

Ok.

> > +int
> > +main (int argc, char *argv[])
> > +{
> > +  char symbol[2 + MAXLEN + 1] = "_Z";
> > +  int seed = -1, seed_set = 0;
> > +  int count = 0, maxcount = -1;
> 
> I think that by default the program should stop.  That will make it
> possible to eventually run as part of "make check".  Give it some
> number of iterations that stops it in a second or so.  You can still
> have it run forever by using -m -1.

On my machine it usually fails in 3-5 seconds, so a 1 second run seems
a little too short.  How does 10 seconds sound?

Thanks,
Gary
Ian Lance Taylor Aug. 12, 2014, 5:28 p.m. UTC | #5
On Tue, Aug 12, 2014 at 10:11 AM, Gary Benson <gbenson@redhat.com> wrote:
> Ian Lance Taylor wrote:
>>
>> I think that by default the program should stop.  That will make it
>> possible to eventually run as part of "make check".  Give it some
>> number of iterations that stops it in a second or so.  You can still
>> have it run forever by using -m -1.
>
> On my machine it usually fails in 3-5 seconds, so a 1 second run seems
> a little too short.  How does 10 seconds sound?

OK, we can start with that, I suppose.

Ian
diff mbox

Patch

Index: libiberty/testsuite/Makefile.in
===================================================================
--- libiberty/testsuite/Makefile.in	(revision 213809)
+++ libiberty/testsuite/Makefile.in	(working copy)
@@ -59,6 +59,10 @@ 
 check-expandargv: test-expandargv
 	./test-expandargv
 
+# Run the demangler fuzzer
+fuzz-demangler: demangler-fuzzer
+	./demangler-fuzzer -m 50000000
+
 TEST_COMPILE = $(CC) @DEFS@ $(LIBCFLAGS) -I.. -I$(INCDIR) $(HDEFINES)
 test-demangle: $(srcdir)/test-demangle.c ../libiberty.a
 	$(TEST_COMPILE) -o test-demangle \
@@ -72,6 +76,10 @@ 
 	$(TEST_COMPILE) -DHAVE_CONFIG_H -I.. -o test-expandargv \
 		$(srcdir)/test-expandargv.c ../libiberty.a
 
+demangler-fuzzer: $(srcdir)/demangler-fuzzer.c ../libiberty.a
+	$(TEST_COMPILE) -o demangler-fuzzer \
+		$(srcdir)/demangler-fuzzer.c ../libiberty.a
+
 # Standard (either GNU or Cygnus) rules we don't use.
 html install-html info install-info clean-info dvi pdf install-pdf \
 install etags tags installcheck:
@@ -81,6 +89,7 @@ 
 	rm -f test-demangle
 	rm -f test-pexecute
 	rm -f test-expandargv
+	rm -f demangler-fuzzer
 	rm -f core
 clean: mostlyclean
 distclean: clean
Index: libiberty/testsuite/demangler-fuzzer.c
===================================================================
--- libiberty/testsuite/demangler-fuzzer.c	(revision 0)
+++ libiberty/testsuite/demangler-fuzzer.c	(revision 0)
@@ -0,0 +1,102 @@ 
+/* Demangler fuzzer.
+
+   Copyright (C) 2014 Free Software Foundation, Inc.
+
+   This file is part of GNU libiberty.
+
+   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 3 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, see <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <demangle.h>
+
+#define MAXLEN 253
+#define ALPMIN 33
+#define ALPMAX 127
+
+static char *program_name;
+
+static void
+print_usage (FILE *fp, int exit_value)
+{
+  fprintf (fp, "Usage: %s [OPTION]...\n", program_name);
+  fprintf (fp, "Options:\n");
+  fprintf (fp, "  -h           Display this message.\n");
+  fprintf (fp, "  -s SEED      Select the random seed to be used.\n");
+  fprintf (fp, "  -m MAXCOUNT  Exit after MAXCOUNT symbols.\n");
+
+  exit (exit_value);
+}
+
+int
+main (int argc, char *argv[])
+{
+  char symbol[2 + MAXLEN + 1] = "_Z";
+  int seed = -1, seed_set = 0;
+  int count = 0, maxcount = -1;
+  int optchr;
+
+  program_name = argv[0];
+
+  do
+    {
+      optchr = getopt (argc, argv, "hs:m:t:");
+      switch (optchr)
+	{
+	case '?':  /* Unrecognized option.  */
+	  print_usage (stderr, 1);
+	  break;
+
+	case 'h':
+	  print_usage (stdout, 0);
+	  break;
+
+	case 's':
+	  seed = atoi (optarg);
+	  seed_set = 1;
+	  break;
+
+	case 'm':
+	  maxcount = atoi (optarg);
+	  break;
+	}
+    }
+  while (optchr != -1);
+
+  if (!seed_set)
+    seed = time (NULL);
+  srand (seed);
+  printf ("%s: seed = %d\n", program_name, seed);
+
+  while (maxcount < 0 || count < maxcount)
+    {
+      char *buffer = symbol + 2;
+      int length, i;
+
+      length = rand () % MAXLEN;
+      for (i = 0; i < length; i++)
+	*buffer++ = (rand () % (ALPMAX - ALPMIN)) + ALPMIN;
+
+      *buffer++ = '\0';
+
+      cplus_demangle (symbol, DMGL_AUTO | DMGL_ANSI | DMGL_PARAMS);
+
+      count++;
+    }
+
+  printf ("%s: successfully demangled %d symbols\n", program_name, count);
+  exit (0);
+}