diff options
author | Andrew Santosa <santosa_1999@yahoo.com> | 2018-06-22 19:50:46 +0800 |
---|---|---|
committer | MartinNowack <martin.nowack@gmail.com> | 2019-03-31 09:53:16 +0100 |
commit | c2a353355a02d392df7ac3f7c47aa4b950c3b943 (patch) | |
tree | bddbcbb4289e918b964992521e6059e7e98d4761 | |
parent | 3c22f088ce92854b9fcb5b41f67bf9a503ec9719 (diff) | |
download | klee-c2a353355a02d392df7ac3f7c47aa4b950c3b943.tar.gz |
Various updates to gen-random-bout.cpp
* Added handling of --sym-arg * Resolved the crash when minimum and maximum number of arguments for --sym-args are equal * Replaced "range" with "n_args" produced by --sym-args * Added model_version variable (constrained to 1), to prevent klee complaining about insufficient input * Allow a single dash to prefix an option * Arrange the elements in the correct order: command-line arguments, files, stdin, stdout * Added test/Runtime/POSIX/GenRandomBout.c test, with a substitution for %gen-random-bout in test/lit.cfg
-rw-r--r-- | test/Runtime/POSIX/GenRandomBout.c | 81 | ||||
-rw-r--r-- | test/lit.cfg | 1 | ||||
-rw-r--r-- | tools/gen-random-bout/gen-random-bout.cpp | 256 |
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; } + |