klee
gen-random-bout.cpp
Go to the documentation of this file.
1//===-- gen-random-bout.cpp -------------------------------------*- C++ -*-===//
2//
3// The KLEE Symbolic Virtual Machine
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#define _FILE_OFFSET_BITS 64
11
12#include <assert.h>
13#include <fcntl.h>
14#include <limits.h>
15#include <stdarg.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <time.h>
22#include <unistd.h>
23
24#include "klee/ADT/KTest.h"
25
26
27#define SMALL_BUFFER_SIZE 64 // To hold "arg<N>" string, temporary
28 // filename, etc.
29
30#define MAX_FILE_SIZES 256
31
32static void error_exit(const char *fmt, ...) {
33 va_list args;
34
35 va_start(args, fmt);
36 vfprintf(stderr, fmt, args);
37 va_end(args);
38
39 exit(1);
40}
41
42static unsigned get_unsigned(char *i) {
43 if (!i) {
44 error_exit("ran out of arguments!\n");
45 }
46 long int n = strtol(i, NULL, 10);
47 if (n < 0 || n == LONG_MIN || n == LONG_MAX) {
48 error_exit("%s:%d: Error in conversion to unsigned: %s\n", __FILE__,
49 __LINE__, i);
50 }
51 return (unsigned)n;
52}
53
54#define MAX 64
55static void push_random_obj(KTest *b, const char *name, unsigned non_zero_bytes,
56 unsigned total_bytes) {
57 KTestObject *o = &b->objects[b->numObjects++];
58 assert(b->numObjects < MAX);
59
60 if ((o->name = strdup(name)) == NULL) {
61 error_exit("%s:%d: strdup() failure\n", __FILE__, __LINE__);
62 }
63 o->numBytes = total_bytes;
64 if ((o->bytes = (unsigned char *)malloc(o->numBytes)) == NULL) {
65 error_exit("%s:%d: malloc() failure\n", __FILE__, __LINE__);
66 }
67
68 unsigned i;
69 for (i = 0; i < non_zero_bytes; i++) {
70 o->bytes[i] = random() % 255 + 1;
71 }
72
73 for (i = non_zero_bytes; i < total_bytes; i++)
74 o->bytes[i] = 0;
75}
76
77static void push_obj(KTest *b, const char *name, unsigned total_bytes,
78 unsigned char *content) {
79 KTestObject *o = &b->objects[b->numObjects++];
80 assert(b->numObjects < MAX);
81
82 if ((o->name = strdup(name)) == NULL) {
83 error_exit("%s:%d: strdup() failure\n", __FILE__, __LINE__);
84 }
85 o->numBytes = total_bytes;
86 if ((o->bytes = (unsigned char *)malloc(total_bytes)) == NULL) {
87 error_exit("%s:%d: malloc() failure\n", __FILE__, __LINE__);
88 }
89 memcpy(o->bytes, content, total_bytes);
90}
91
92static void push_range(KTest *b, const char *name, unsigned value) {
93 push_obj(b, name, 4, (unsigned char *)&value);
94}
95
96void create_stat(size_t size, struct stat *s) {
97 char filename_template[] = "/tmp/klee-gen-random-bout-XXXXXX";
98 char *filename;
99 int fd;
100 unsigned char *buf;
101
102 if ((filename = strdup(filename_template)) == NULL) {
103 error_exit("%s:%d: strdup() failure\n", __FILE__, __LINE__);
104 }
105
106 if (((fd = mkstemp(filename)) < 0) ||
107 ((fchmod(fd, S_IRWXU | S_IRWXG | S_IRWXO)) < 0)) {
108 error_exit("%s:%d: Failure creating %s\n", __FILE__, __LINE__, filename);
109 }
110
111 if ((buf = (unsigned char *)malloc(size)) == NULL) {
112 error_exit("%s:%d: malloc() failure\n", __FILE__, __LINE__);
113 }
114
115 if (write(fd, memset(buf, 0, size), size) != (int)size) {
116 free(buf);
117 free(filename);
118 error_exit("%s:%d: Error writing %s\n", __FILE__, __LINE__, filename);
119 }
120
121 fstat(fd, s);
122
123 close(fd);
124
125 unlink(filename);
126
127 free(filename);
128 free(buf);
129}
130
131int main(int argc, char *argv[]) {
132 unsigned i, narg;
133 unsigned sym_stdout = 0;
134 unsigned stdin_size = 0;
135 int total_args = 0;
136 unsigned total_files = 0;
137 unsigned file_sizes[MAX_FILE_SIZES];
138 char **argv_copy;
139 char *bout_file = NULL;
140
141 if (argc < 2) {
143 "Usage: %s <random-seed> <argument-types>\n"
144 " If <random-seed> is 0, time(NULL)*getpid() is used as a seed\n"
145 " <argument-types> are the ones accepted by KLEE: --sym-args, "
146 "--sym-files etc. and --bout-file <filename> for the output file (default: random.bout).\n"
147 " Ex: %s 100 --sym-args 0 2 2 --sym-files 1 8\n",
148 argv[0], argv[0]);
149 }
150
151 unsigned seed = atoi(argv[1]);
152 if (seed)
153 srandom(seed);
154 else
155 srandom(time(NULL) * getpid());
156
157 if ((argv_copy = (char **) malloc((argc - 1) * sizeof(char *))) == NULL) {
158 error_exit("%s:%d: malloc() failure\n", __FILE__, __LINE__);
159 }
160 argv_copy[0] = argv[0];
161 for (i = 2; i < (unsigned)argc; ++i) {
162 argv_copy[i - 1] = argv[i];
163 }
164
165 KTest b;
166 b.numArgs = argc - 1;
167 b.args = argv_copy;
168 b.symArgvs = 0;
169 b.symArgvLen = 0;
170
171 b.numObjects = 0;
172 b.objects = (KTestObject *)malloc(MAX * sizeof *b.objects);
173
174 for (i = 2; i < (unsigned)argc; i++) {
175 if (strcmp(argv[i], "--sym-arg") == 0 || strcmp(argv[i], "-sym-arg") == 0) {
176 unsigned nbytes = get_unsigned(argv[++i]);
177
178 // A little different than how klee does it but more natural for random.
179 char arg[SMALL_BUFFER_SIZE];
180 unsigned x = random() % (nbytes + 1);
181
182 snprintf(arg, SMALL_BUFFER_SIZE, "arg%d", total_args++);
183 push_random_obj(&b, arg, x, nbytes + 1);
184 } else if (strcmp(argv[i], "--sym-args") == 0 ||
185 strcmp(argv[i], "-sym-args") == 0) {
186 unsigned lb = get_unsigned(argv[++i]);
187 unsigned ub = get_unsigned(argv[++i]);
188 unsigned nbytes = get_unsigned(argv[++i]);
189
190 if (ub < lb) {
191 error_exit("--sym-args first argument should be no more than its "
192 "second argument\n");
193 }
194
195 narg = random() % (ub - lb + 1) + lb;
196 push_range(&b, "n_args", narg);
197
198 while (narg-- > 0) {
199 unsigned x = random() % (nbytes + 1);
200
201 // A little different than how klee does it but more natural
202 // for random.
203 char arg[SMALL_BUFFER_SIZE];
204
205 snprintf(arg, SMALL_BUFFER_SIZE, "arg%d", total_args++);
206 push_random_obj(&b, arg, x, nbytes + 1);
207 }
208 } else if (strcmp(argv[i], "--sym-stdout") == 0 ||
209 strcmp(argv[i], "-sym-stdout") == 0) {
210 sym_stdout = 1;
211 } else if (strcmp(argv[i], "--sym-stdin") == 0 ||
212 strcmp(argv[i], "-sym-stdin") == 0) {
213 stdin_size = get_unsigned(argv[++i]);
214 } else if (strcmp(argv[i], "--sym-files") == 0 ||
215 strcmp(argv[i], "-sym-files") == 0) {
216 unsigned nfiles = get_unsigned(argv[++i]);
217 unsigned nbytes = get_unsigned(argv[++i]);
218
219 total_files = 0;
220 while (nfiles-- > 0) {
221 if (total_files >= MAX_FILE_SIZES) {
222 error_exit("%s:%d: Maximum number of file sizes exceeded (%d)\n",
223 __FILE__, __LINE__, MAX_FILE_SIZES);
224 }
225 file_sizes[total_files++] = nbytes;
226 }
227
228 } else if (strcmp(argv[i], "--bout-file") == 0 ||
229 strcmp(argv[i], "-bout-file") == 0) {
230 if ((unsigned)argc == ++i)
231 error_exit("Missing file name for --bout-file");
232
233 bout_file = argv[i];
234 } else {
235 error_exit("Unexpected option <%s>\n", argv[i]);
236 }
237 }
238
239 for (i = 0; i < total_files; ++i) {
240 char filename[] = "A-data";
241 char file_stat[] = "A-data-stat";
242 unsigned nbytes;
243 struct stat s;
244
245 if (i >= MAX_FILE_SIZES) {
246 fprintf(stderr, "%s:%d: Maximum number of file sizes exceeded (%d)\n",
247 __FILE__, __LINE__, MAX_FILE_SIZES);
248 exit(1);
249 }
250 nbytes = file_sizes[i];
251
252 filename[0] += i;
253 file_stat[0] += i;
254
255 create_stat(nbytes, &s);
256
257 push_random_obj(&b, filename, nbytes, nbytes);
258 push_obj(&b, file_stat, sizeof(struct stat), (unsigned char *)&s);
259 }
260
261 if (stdin_size) {
262 struct stat s;
263
264 // Using disk file works well with klee-replay.
265 create_stat(stdin_size, &s);
266
267 push_random_obj(&b, "stdin", stdin_size, stdin_size);
268 push_obj(&b, "stdin-stat", sizeof(struct stat), (unsigned char *)&s);
269 }
270 if (sym_stdout) {
271 struct stat s;
272
273 // Using disk file works well with klee-replay.
274 create_stat(1024, &s);
275
276 push_random_obj(&b, "stdout", 1024, 1024);
277 push_obj(&b, "stdout-stat", sizeof(struct stat), (unsigned char *)&s);
278 }
279 push_range(&b, "model_version", 1);
280
281 if (!kTest_toFile(&b, bout_file ? bout_file : "random.bout")) {
282 error_exit("Error in storing data into random.bout\n");
283 }
284
285 for (i = 0; i < b.numObjects; ++i) {
286 free(b.objects[i].name);
287 free(b.objects[i].bytes);
288 }
289
290 free(b.objects);
291
292 free(argv_copy);
293 return 0;
294}
295
int kTest_toFile(KTest *bo, const char *path)
Definition: KTest.cpp:178
static void error_exit(const char *fmt,...)
int main(int argc, char *argv[])
#define MAX_FILE_SIZES
#define MAX
static unsigned get_unsigned(char *i)
void create_stat(size_t size, struct stat *s)
static void push_obj(KTest *b, const char *name, unsigned total_bytes, unsigned char *content)
static void push_random_obj(KTest *b, const char *name, unsigned non_zero_bytes, unsigned total_bytes)
static void push_range(KTest *b, const char *name, unsigned value)
#define SMALL_BUFFER_SIZE
char * name
Definition: KTest.h:19
unsigned char * bytes
Definition: KTest.h:21
unsigned numBytes
Definition: KTest.h:20
Definition: KTest.h:25
unsigned symArgvLen
Definition: KTest.h:33
unsigned numObjects
Definition: KTest.h:35
KTestObject * objects
Definition: KTest.h:36
unsigned numArgs
Definition: KTest.h:29
unsigned symArgvs
Definition: KTest.h:32
char ** args
Definition: KTest.h:30