about summary refs log tree commit diff homepage
diff options
context:
space:
mode:
-rw-r--r--test/Runtime/POSIX/GenRandomBout.c81
-rw-r--r--test/lit.cfg1
-rw-r--r--tools/gen-random-bout/gen-random-bout.cpp256
3 files changed, 286 insertions, 52 deletions
diff --git a/test/Runtime/POSIX/GenRandomBout.c b/test/Runtime/POSIX/GenRandomBout.c
new file mode 100644
index 00000000..8f1199cb
--- /dev/null
+++ b/test/Runtime/POSIX/GenRandomBout.c
@@ -0,0 +1,81 @@
+// -- Core testing commands
+// RUN: rm -rf %t.out
+// RUN: mkdir -p %t.out && cd %t.out
+// RUN: %gen-random-bout 100 -sym-arg 4 -sym-files 2 20 -sym-arg 5 -sym-stdin 8 -sym-stdout -sym-arg 6 -sym-args 1 4 5
+// RUN: %cc %s -O0 -o %t
+// RUN: %klee-replay %t file.bout 2>&1 | grep "klee-replay: EXIT STATUS: NORMAL"
+//
+// -- Option error handling tests
+// RUN: bash -c '%gen-random-bout || :' 2>&1 | grep "Usage"
+// RUN: bash -c '%gen-random-bout 0 --unexpected-option || :' 2>&1 | grep "Unexpected"
+// RUN: bash -c '%gen-random-bout 100 --sym-args 5 3 || :' 2>&1 | grep "ran out of"
+// RUN: bash -c '%gen-random-bout 100 --sym-args 5 3 10 || :' 2>&1 | grep "should be no more"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+int check_fd(int fd, const int file_size) {
+  struct stat fs;
+
+  if (fstat(fd, &fs) < 0)
+    return -1;
+
+  if (fs.st_size != file_size)
+    return -1;
+
+  return 0;
+}
+
+int check_file(const char *file_name, const int file_size) {
+  int fd;
+
+  if ((fd = open(file_name, O_RDONLY)) < 0)
+    return -1;
+
+  if (check_fd(fd, file_size) < 0)
+    return -1;
+
+  close(fd);
+
+  return 0;
+}
+
+int main(int argc, char **argv) {
+  int i = 0;
+
+  if (argc < 4 || argc > 7)
+    return 1;
+
+  if (strlen(argv[1]) > 4)
+    return 1;
+
+  if (strlen(argv[2]) > 5)
+    return 1;
+
+  if (strlen(argv[3]) > 6)
+    return 1;
+
+  for (i = 4; i < argc; ++i)
+    if (strlen(argv[i]) > 5)
+      return 1;
+
+  if (check_file("A", 20) < 0)
+    return 1;
+
+  if (check_file("B", 20) < 0)
+    return 1;
+
+  if (check_fd(0, 8) < 0)
+    return 1;
+
+  if (check_fd(1, 1024) < 0)
+    return 1;
+
+  printf("All size tests passed\n");
+
+  return 0;
+}
diff --git a/test/lit.cfg b/test/lit.cfg
index f6c7cd68..131369f8 100644
--- a/test/lit.cfg
+++ b/test/lit.cfg
@@ -139,6 +139,7 @@ subs = [ ('%kleaver', 'kleaver', kleaver_extra_params),
          ('%klee-replay', 'klee-replay', ''),
          ('%klee','klee', klee_extra_params),
          ('%ktest-tool', 'ktest-tool', ''),
+         ('%gen-random-bout', 'gen-random-bout', ''),
          ('%gen-bout', 'gen-bout', '')
 ]
 for s,basename,extra_args in subs:
diff --git a/tools/gen-random-bout/gen-random-bout.cpp b/tools/gen-random-bout/gen-random-bout.cpp
index fca24008..5f65c9bb 100644
--- a/tools/gen-random-bout/gen-random-bout.cpp
+++ b/tools/gen-random-bout/gen-random-bout.cpp
@@ -8,6 +8,9 @@
 //===----------------------------------------------------------------------===//
 
 #include <assert.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -22,55 +25,127 @@
 #define stat64 stat
 #endif
 
-// --sym-args 0 1 10 --sym-args 0 2 2 --sym-files 1 8 --sym-stdout
-static int getint(char *i) {
+#define SMALL_BUFFER_SIZE 64 // To hold "arg<N>" string, temporary
+                             // filename, etc.
+
+#define MAX_FILE_SIZES 256
+
+static void error_exit(const char *fmt, ...) {
+  va_list args;
+
+  va_start(args, fmt);
+  vfprintf(stderr, fmt, args);
+  va_end(args);
+
+  exit(1);
+}
+
+static unsigned get_unsigned(char *i) {
   if(!i) {
-    fprintf(stderr, "ran out of arguments!\n");
-    assert(i);
+    error_exit("ran out of arguments!\n");
   }
-  return atoi(i);
+  long int n = strtol(i, NULL, 10);
+  if (n < 0 || n == LONG_MIN || n == LONG_MAX) {
+    error_exit("%s:%d: Error in conversion to unsigned: %s\n", __FILE__,
+               __LINE__, i);
+  }
+  return (unsigned)n;
 }
 
 #define MAX 64
-static void push_obj(KTest *b, const char *name, unsigned non_zero_bytes, 
-                     unsigned total_bytes) {
+static void push_random_obj(KTest *b, const char *name, unsigned non_zero_bytes,
+                            unsigned total_bytes) {
   KTestObject *o = &b->objects[b->numObjects++];
   assert(b->numObjects < MAX);
 
-  o->name = strdup(name);
+  if ((o->name = strdup(name)) == NULL) {
+    error_exit("%s:%d: strdup() failure\n", __FILE__, __LINE__);
+  }
   o->numBytes = total_bytes;
-  o->bytes = (unsigned char *)malloc(o->numBytes);
+  if ((o->bytes = (unsigned char *)malloc(o->numBytes)) == NULL) {
+    error_exit("%s:%d: malloc() failure\n", __FILE__, __LINE__);
+  }
 
   unsigned i;
-  for(i = 0; i < non_zero_bytes; i++)
-    o->bytes[i] = random();
+  for (i = 0; i < non_zero_bytes; i++) {
+    o->bytes[i] = random() % 255 + 1;
+  }
 
   for(i = non_zero_bytes; i < total_bytes; i++)
     o->bytes[i] = 0;
 }
 
-
-static void push_range(KTest *b, const char *name, unsigned value) {
+static void push_obj(KTest *b, const char *name, unsigned total_bytes,
+                     unsigned char *content) {
   KTestObject *o = &b->objects[b->numObjects++];
   assert(b->numObjects < MAX);
 
-  o->name = strdup(name);
-  o->numBytes = 4;
-  o->bytes = (unsigned char *)malloc(o->numBytes);
+  if ((o->name = strdup(name)) == NULL) {
+    error_exit("%s:%d: strdup() failure\n", __FILE__, __LINE__);
+  }
+  o->numBytes = total_bytes;
+  if ((o->bytes = (unsigned char *)malloc(total_bytes)) == NULL) {
+    error_exit("%s:%d: malloc() failure\n", __FILE__, __LINE__);
+  }
+  memcpy(o->bytes, content, total_bytes);
+}
+
+static void push_range(KTest *b, const char *name, unsigned value) {
+  push_obj(b, name, 4, (unsigned char *)&value);
+}
+
+void create_stat(size_t size, struct stat64 *s) {
+  char filename_template[] = "/tmp/klee-gen-random-bout-XXXXXX";
+  char *filename;
+  int fd;
+  unsigned char *buf;
+
+  if ((filename = strdup(filename_template)) == NULL) {
+    error_exit("%s:%d: strdup() failure\n", __FILE__, __LINE__);
+  }
+
+  if (((fd = mkstemp(filename)) < 0) ||
+      ((fchmod(fd, S_IRWXU | S_IRWXG | S_IRWXO)) < 0)) {
+    error_exit("%s:%d: Failure creating %s\n", __FILE__, __LINE__, filename);
+  }
+
+  if ((buf = (unsigned char *)malloc(size)) == NULL) {
+    error_exit("%s:%d: malloc() failure\n", __FILE__, __LINE__);
+  }
+
+  if (write(fd, memset(buf, 0, size), size) != (int)size) {
+    free(buf);
+    free(filename);
+    error_exit("%s:%d: Error writing %s\n", __FILE__, __LINE__, filename);
+  }
+
+  fstat64(fd, s);
+
+  close(fd);
 
-  *(unsigned*)o->bytes = value;
+  unlink(filename);
+
+  free(filename);
+  free(buf);
 }
 
 int main(int argc, char *argv[]) {
   unsigned i, narg;
   unsigned sym_stdout = 0;
+  unsigned stdin_size = 0;
+  int total_args = 0;
+  unsigned total_files = 0;
+  unsigned file_sizes[MAX_FILE_SIZES];
+  char **argv_copy;
 
   if (argc < 2) {
-    fprintf(stderr, "Usage: %s <random-seed> <argument-types>\n", argv[0]);
-    fprintf(stderr, "       If <random-seed> is 0, time(NULL)*getpid() is used as a seed\n");
-    fprintf(stderr, "       <argument-types> are the ones accepted by KLEE: --sym-args, --sym-files etc.\n");
-    fprintf(stderr, "   Ex: %s 100 --sym-args 0 2 2 --sym-files 1 8\n", argv[0]);
-    exit(1);
+    error_exit(
+        "Usage: %s <random-seed> <argument-types>\n"
+        "       If <random-seed> is 0, time(NULL)*getpid() is used as a seed\n"
+        "       <argument-types> are the ones accepted by KLEE: --sym-args, "
+        "--sym-files etc.\n"
+        "   Ex: %s 100 --sym-args 0 2 2 --sym-files 1 8\n",
+        argv[0], argv[0]);
   }
 
   unsigned seed = atoi(argv[1]);
@@ -78,9 +153,17 @@ int main(int argc, char *argv[]) {
     srandom(seed);
   else srandom(time(NULL) * getpid());
 
+  if ((argv_copy = (char **)malloc((argc - 1) * sizeof(char *))) == NULL) {
+    error_exit("%s:%d: malloc() failure\n", __FILE__, __LINE__);
+  }
+  argv_copy[0] = argv[0];
+  for (i = 2; i < (unsigned) argc; ++i) {
+    argv_copy[i - 1] = argv[i];
+  }
+
   KTest b;
-  b.numArgs = argc;
-  b.args = argv;
+  b.numArgs = argc - 1;
+  b.args = argv_copy;
   b.symArgvs = 0;
   b.symArgvLen = 0;
 
@@ -88,50 +171,119 @@ int main(int argc, char *argv[]) {
   b.objects = (KTestObject *)malloc(MAX * sizeof *b.objects);
 
   for(i = 2; i < (unsigned)argc; i++) {
-    if(strcmp(argv[i], "--sym-args") == 0) {
-      unsigned lb = getint(argv[++i]);
-      unsigned ub = getint(argv[++i]);
-      unsigned nbytes = getint(argv[++i]);
+    if (strcmp(argv[i], "--sym-arg") == 0 || strcmp(argv[i], "-sym-arg") == 0) {
+      unsigned nbytes = get_unsigned(argv[++i]);
+
+      // A little different than how klee does it but more natural for random.
+      char arg[SMALL_BUFFER_SIZE];
+      unsigned x = random() % (nbytes + 1);
+
+      snprintf(arg, SMALL_BUFFER_SIZE, "arg%d", total_args++);
+      push_random_obj(&b, arg, x, nbytes + 1);
+    } else if (strcmp(argv[i], "--sym-args") == 0 ||
+               strcmp(argv[i], "-sym-args") == 0) {
+      unsigned lb = get_unsigned(argv[++i]);
+      unsigned ub = get_unsigned(argv[++i]);
+      unsigned nbytes = get_unsigned(argv[++i]);
+
+      if (ub < lb) {
+        error_exit("--sym-args first argument should be no more than its "
+                   "second argument\n");
+      }
 
-      narg = random() % (ub - lb) + lb;
-      push_range(&b, "range", narg);
+
+      narg = random() % (ub - lb + 1) + lb;
+      push_range(&b, "n_args", narg);
 
       while(narg-- > 0) {
         unsigned x = random() % (nbytes + 1);
 
         // A little different than how klee does it but more natural
         // for random.
-        static int total_args;
-        char arg[1024];
+        char arg[SMALL_BUFFER_SIZE];
 
-        sprintf(arg, "arg%d", total_args++);
-        push_obj(&b, arg, x, nbytes+1);
-      }
-    } else if(strcmp(argv[i], "--sym-stdout") == 0) {
-      if(!sym_stdout) {
-        sym_stdout = 1;
-        push_obj(&b, "stdout", 1024, 1024);
-        push_obj(&b, "stdout-stat", sizeof(struct stat64), 
-                 sizeof(struct stat64));
+        snprintf(arg, SMALL_BUFFER_SIZE, "arg%d", total_args++);
+        push_random_obj(&b, arg, x, nbytes + 1);
       }
-    } else if(strcmp(argv[i], "--sym-files") == 0) {
-      unsigned nfiles = getint(argv[++i]);
-      unsigned nbytes = getint(argv[++i]);
+    } else if (strcmp(argv[i], "--sym-stdout") == 0 ||
+               strcmp(argv[i], "-sym-stdout") == 0) {
+      sym_stdout = 1;
+    } else if (strcmp(argv[i], "--sym-stdin") == 0 ||
+               strcmp(argv[i], "-sym-stdin") == 0) {
+      stdin_size = get_unsigned(argv[++i]);
+    } else if (strcmp(argv[i], "--sym-files") == 0 ||
+               strcmp(argv[i], "-sym-files") == 0) {
+      unsigned nfiles = get_unsigned(argv[++i]);
+      unsigned nbytes = get_unsigned(argv[++i]);
 
+      total_files = 0;
       while(nfiles-- > 0) {
-        push_obj(&b, "file", nbytes, nbytes);
-        push_obj(&b, "file-stat", sizeof(struct stat64), sizeof(struct stat64));
+        if (total_files >= MAX_FILE_SIZES) {
+          error_exit("%s:%d: Maximum number of file sizes exceeded (%d)\n",
+                     __FILE__, __LINE__, MAX_FILE_SIZES);
+        }
+        file_sizes[total_files++] = nbytes;
       }
 
-      push_obj(&b, "stdin", nbytes, nbytes);
-      push_obj(&b, "stdin-stat", sizeof(struct stat64), sizeof(struct stat64));
     } else {
-      fprintf(stderr, "unexpected option <%s>\n", argv[i]);
-      assert(0);
+      error_exit("Unexpected option <%s>\n", argv[i]);
     }
   }
 
-  if (!kTest_toFile(&b, "file.bout"))
-    assert(0);
+  for (i = 0; i < total_files; ++i) {
+    char filename[] = "A-data";
+    char file_stat[] = "A-data-stat";
+    unsigned nbytes;
+    struct stat64 s;
+
+    if (i >= MAX_FILE_SIZES) {
+      fprintf(stderr, "%s:%d: Maximum number of file sizes exceeded (%d)\n",
+              __FILE__, __LINE__, MAX_FILE_SIZES);
+      exit(1);
+    }
+    nbytes = file_sizes[i];
+
+    filename[0] += i;
+    file_stat[0] += i;
+
+    create_stat(nbytes, &s);
+
+    push_random_obj(&b, filename, nbytes, nbytes);
+    push_obj(&b, file_stat, sizeof(struct stat64), (unsigned char *)&s);
+  }
+
+  if (stdin_size) {
+    struct stat64 s;
+
+    // Using disk file works well with klee-replay.
+    create_stat(stdin_size, &s);
+
+    push_random_obj(&b, "stdin", stdin_size, stdin_size);
+    push_obj(&b, "stdin-stat", sizeof(struct stat64), (unsigned char *)&s);
+  }
+  if (sym_stdout) {
+    struct stat64 s;
+
+    // Using disk file works well with klee-replay.
+    create_stat(1024, &s);
+
+    push_random_obj(&b, "stdout", 1024, 1024);
+    push_obj(&b, "stdout-stat", sizeof(struct stat64), (unsigned char *)&s);
+  }
+  push_range(&b, "model_version", 1);
+
+  if (!kTest_toFile(&b, "file.bout")) {
+    error_exit("Error in storing data into file.bout\n");
+  }
+
+  for (i = 0; i < b.numObjects; ++i) {
+    free(b.objects[i].name);
+    free(b.objects[i].bytes);
+  }
+
+  free(b.objects);
+
+  free(argv_copy);
   return 0;
 }
+