1/* Fuzz-testing of libgccjit API. 2 Currently this triggers internal compiler errors, typically due to type 3 mismatches. */ 4#include <limits.h> 5#include <stdlib.h> 6#include <stdio.h> 7#include <assert.h> 8 9#include "libgccjit.h" 10 11#define TEST_PROVIDES_MAIN 12#include "harness.h" 13 14typedef struct fuzzer 15{ 16 gcc_jit_context *ctxt; 17 18 unsigned int seed; 19 20 int num_types; 21 gcc_jit_type **types; 22 23 int num_globals; 24 gcc_jit_lvalue **globals; 25 26 int num_funcs; 27 gcc_jit_function **funcs; 28 29} fuzzer; 30 31static void 32fuzzer_init (fuzzer *f, gcc_jit_context *ctxt, unsigned int seed); 33 34static int 35fuzzer_randrange (fuzzer *f, int min, int max); 36 37static gcc_jit_location * 38get_random_location (fuzzer *f); 39 40static gcc_jit_type * 41get_random_type (fuzzer *f); 42 43static gcc_jit_type * 44make_random_type (fuzzer *f); 45 46static gcc_jit_lvalue * 47make_random_global (fuzzer *f); 48 49static gcc_jit_function * 50make_random_function (fuzzer *f); 51 52typedef struct function_fuzzer 53{ 54 fuzzer *f; 55 56 int num_params; 57 gcc_jit_param **params; 58 59 gcc_jit_function *fn; 60 61 int num_locals; 62 gcc_jit_lvalue **locals; 63 64 gcc_jit_block *block; 65 66} function_fuzzer; 67 68static void 69function_fuzzer_add_stmt (function_fuzzer *ff); 70 71static gcc_jit_lvalue * 72get_random_lvalue (function_fuzzer *ff, int max_depth); 73 74static gcc_jit_rvalue * 75get_random_rvalue (function_fuzzer *ff, int max_depth); 76 77/* fuzzer defns. */ 78 79static void 80fuzzer_init (fuzzer *f, gcc_jit_context *ctxt, unsigned int seed) 81{ 82 int i; 83 memset (f, 0, sizeof (*f)); 84 f->ctxt = ctxt; 85 f->seed = seed; 86 87 int num_types = fuzzer_randrange (f, 5, 10); 88 f->types = malloc (num_types * sizeof (gcc_jit_type *)); 89 90 int num_funcs = fuzzer_randrange (f, 3, 5); 91 f->funcs = malloc (num_funcs * sizeof (gcc_jit_function *)); 92 93 int num_globals = fuzzer_randrange (f, 5, 10); 94 f->globals = malloc (num_globals * sizeof (gcc_jit_lvalue *)); 95 96 for (i = 0; i < num_types; i++) 97 { 98 gcc_jit_type *type = make_random_type (f); 99 assert (type); 100 f->types[f->num_types++] = type; 101 } 102 103 for (i = 0; i < num_globals; i++) 104 f->globals[f->num_globals++] = make_random_global (f); 105 106 for (i = 0; i < num_funcs; i++) 107 f->funcs[f->num_funcs++] = make_random_function (f); 108 109 /* Now clean out f. */ 110 free (f->types); 111 free (f->funcs); 112 free (f->globals); 113} 114 115/* Get random int in inclusive range [min, max]. */ 116 117static int fuzzer_randrange (fuzzer *f, int min, int max) 118{ 119 assert (min <= max); 120 int i = rand_r (&f->seed); 121 int result = (i % (max + 1 - min)) + min; 122 assert (result >= min); 123 assert (result <= max); 124 return result; 125} 126 127static gcc_jit_location * 128get_random_location (fuzzer *f) 129{ 130 const char *filename = NULL; 131 132 if (fuzzer_randrange (f, 0, 1)) 133 return NULL; 134 135 switch (fuzzer_randrange (f, 1, 2)) 136 { 137 case 1: 138 filename = "foo.c"; 139 break; 140 case 2: 141 filename = "bar.c"; 142 break; 143 } 144 145 return gcc_jit_context_new_location (f->ctxt, 146 filename, 147 fuzzer_randrange (f, 1, 1000), 148 fuzzer_randrange (f, 1, 1000)); 149} 150 151const enum gcc_jit_types types[] = { 152 GCC_JIT_TYPE_VOID, 153 154 GCC_JIT_TYPE_VOID_PTR, 155 156 GCC_JIT_TYPE_CHAR, 157 GCC_JIT_TYPE_SIGNED_CHAR, 158 GCC_JIT_TYPE_UNSIGNED_CHAR, 159 160 GCC_JIT_TYPE_SHORT, 161 GCC_JIT_TYPE_UNSIGNED_SHORT, 162 163 GCC_JIT_TYPE_INT, 164 GCC_JIT_TYPE_UNSIGNED_INT, 165 166 GCC_JIT_TYPE_LONG, 167 GCC_JIT_TYPE_UNSIGNED_LONG, 168 169 GCC_JIT_TYPE_LONG_LONG, 170 GCC_JIT_TYPE_UNSIGNED_LONG_LONG, 171 172 GCC_JIT_TYPE_FLOAT, 173 GCC_JIT_TYPE_DOUBLE, 174 GCC_JIT_TYPE_LONG_DOUBLE, 175 176 GCC_JIT_TYPE_CONST_CHAR_PTR, 177 178 GCC_JIT_TYPE_SIZE_T, 179 180 GCC_JIT_TYPE_FILE_PTR 181}; 182#define NUM_TYPES (sizeof(types)/sizeof(types[0])) 183 184static gcc_jit_type * 185get_random_type (fuzzer *f) 186{ 187 int i = fuzzer_randrange (f, 0, (NUM_TYPES - 1) + f->num_types); 188 if (i < NUM_TYPES) 189 return gcc_jit_context_get_type (f->ctxt, types[i]); 190 assert ((i - NUM_TYPES) < f->num_types); 191 assert (f->types[i - NUM_TYPES]); 192 return f->types[i - NUM_TYPES]; 193} 194 195static gcc_jit_type * 196make_random_type (fuzzer *f) 197{ 198 switch (fuzzer_randrange (f, 0, 5)) 199 { 200 case 0: 201 return gcc_jit_type_get_pointer (get_random_type (f)); 202 case 1: 203 return gcc_jit_type_get_const (get_random_type (f)); 204 default: 205 { 206 /* Create a struct. */ 207 int num_fields = fuzzer_randrange (f, 0, 10); 208 gcc_jit_field **fields = \ 209 malloc (num_fields * sizeof (gcc_jit_field *)); 210 int i; 211 for (i = 0; i < num_fields ; i++) 212 { 213 char field_name[256]; 214 sprintf (field_name, "field%i", i); 215 fields[i] = gcc_jit_context_new_field (f->ctxt, 216 get_random_location (f), 217 get_random_type (f), 218 field_name); 219 } 220 char struct_name[256]; 221 sprintf (struct_name, "s%i", f->num_types); 222 gcc_jit_struct *struct_ = \ 223 gcc_jit_context_new_struct_type (f->ctxt, 224 get_random_location (f), 225 struct_name, 226 num_fields, 227 fields); 228 free (fields); 229 return gcc_jit_struct_as_type (struct_); 230 } 231 } 232} 233 234static gcc_jit_lvalue * 235make_random_global (fuzzer *f) 236{ 237 char global_name[256]; 238 sprintf (global_name, "g%i", f->num_globals); 239 return gcc_jit_context_new_global (f->ctxt, 240 get_random_location (f), 241 GCC_JIT_GLOBAL_EXPORTED, 242 get_random_type (f), 243 global_name); 244} 245 246static gcc_jit_function * 247make_random_function (fuzzer *f) 248{ 249 char func_name[256]; 250 sprintf (func_name, "fn%i", f->num_funcs); 251 252 function_fuzzer *ff = malloc (sizeof (function_fuzzer)); 253 memset (ff, 0, sizeof (*ff)); 254 255 ff->f = f; 256 257 ff->num_params = fuzzer_randrange (f, 0, 10); 258 ff->params = malloc (ff->num_params * sizeof (gcc_jit_param *)); 259 int i; 260 for (i = 0; i < ff->num_params; i++) 261 { 262 char param_name[256]; 263 sprintf (param_name, "param%i", i); 264 ff->params[i] = \ 265 gcc_jit_context_new_param (f->ctxt, 266 get_random_location (f), 267 get_random_type (f), 268 param_name); 269 } 270 271 enum gcc_jit_function_kind kind = 272 ((enum gcc_jit_function_kind) 273 fuzzer_randrange (f, 0, GCC_JIT_FUNCTION_IMPORTED)); 274 275 ff->fn = \ 276 gcc_jit_context_new_function ( 277 f->ctxt, 278 get_random_location (f), 279 kind, 280 get_random_type (f), 281 func_name, 282 ff->num_params, 283 ff->params, 284 fuzzer_randrange (f, 0, 1)); 285 ff->block = gcc_jit_function_new_block (ff->fn, NULL); 286 287 /* Create locals. */ 288 if (kind != GCC_JIT_FUNCTION_IMPORTED) 289 { 290 ff->num_locals = fuzzer_randrange (f, 0, 10); 291 ff->locals = malloc (ff->num_locals * sizeof (gcc_jit_lvalue *)); 292 for (i = 0; i < ff->num_locals; i++) 293 { 294 char local_name[256]; 295 sprintf (local_name, "local%i", i); 296 ff->locals[i] = 297 gcc_jit_function_new_local (ff->fn, 298 get_random_location (f), 299 get_random_type (f), 300 local_name); 301 } 302 } 303 /* TODO: use locals. */ 304 305 if (kind != GCC_JIT_FUNCTION_IMPORTED) 306 { 307 /* TODO: create body */ 308 int num_stmts = fuzzer_randrange (f, 0, 10); 309 for (i = 0; i < num_stmts; i++) 310 function_fuzzer_add_stmt (ff); 311 } 312 313 gcc_jit_block_end_with_return (ff->block, NULL, get_random_rvalue (ff, 3)); 314 315 316 gcc_jit_function *result = ff->fn; 317 318 free (ff->locals); 319 free (ff->params); 320 free (ff); 321 322 return result; 323} 324 325/* function_fuzzer defns. */ 326 327static void function_fuzzer_add_stmt (function_fuzzer *ff) 328{ 329 gcc_jit_block_add_eval (ff->block, 330 get_random_location (ff->f), 331 get_random_rvalue (ff, 4)); 332 gcc_jit_block_add_assignment (ff->block, 333 get_random_location (ff->f), 334 get_random_lvalue (ff, 4), 335 get_random_rvalue (ff, 4)); 336 /* TODO: place more kinds of statement */ 337 /* TODO: labels */ 338} 339 340static gcc_jit_lvalue *get_random_lvalue (function_fuzzer *ff, int max_depth) 341{ 342 int choice = fuzzer_randrange (ff->f, 0, 343 ff->num_params 344 + ff->num_locals 345 + ff->f->num_globals - 1); 346 if (choice < ff->num_params) 347 return gcc_jit_param_as_lvalue (ff->params[choice]); 348 choice -= ff->num_params; 349 350 if (choice < ff->num_locals) 351 return ff->locals[choice]; 352 choice -= ff->num_locals; 353 354 assert (choice < ff->f->num_globals); 355 return ff->f->globals[choice]; 356} 357 358static gcc_jit_rvalue *get_random_rvalue (function_fuzzer *ff, int max_depth) 359{ 360 int use_lvalue = fuzzer_randrange (ff->f, 0, 1); 361 if (use_lvalue) 362 return gcc_jit_lvalue_as_rvalue (get_random_lvalue (ff, max_depth)); 363 364 int choice = fuzzer_randrange (ff->f, 0, 1); 365 366 /* Compound op: */ 367 switch (choice) 368 { 369 case 0: 370 return gcc_jit_context_new_string_literal (ff->f->ctxt, "hello"); 371 case 1: 372 return gcc_jit_context_new_rvalue_from_int ( 373 ff->f->ctxt, 374 get_random_type (ff->f), 375 fuzzer_randrange (ff->f, 0, INT_MAX)); 376 case 2: 377 return gcc_jit_context_new_rvalue_from_double ( 378 ff->f->ctxt, 379 get_random_type (ff->f), 380 ((double)fuzzer_randrange (ff->f, 0, INT_MAX)) 381 / (double)fuzzer_randrange (ff->f, 0, INT_MAX)); 382 case 3: 383 return gcc_jit_context_new_unary_op ( 384 ff->f->ctxt, 385 get_random_location (ff->f), 386 ((enum gcc_jit_unary_op) 387 fuzzer_randrange (ff->f, 0, GCC_JIT_UNARY_OP_LOGICAL_NEGATE)), 388 get_random_type (ff->f), 389 get_random_rvalue (ff, max_depth - 1)); 390 case 4: 391 return gcc_jit_context_new_binary_op ( 392 ff->f->ctxt, 393 get_random_location (ff->f), 394 ((enum gcc_jit_binary_op) 395 fuzzer_randrange (ff->f, 0, GCC_JIT_BINARY_OP_LOGICAL_OR)), 396 get_random_type (ff->f), 397 get_random_rvalue (ff, max_depth - 1), 398 get_random_rvalue (ff, max_depth - 1)); 399 case 5: 400 return gcc_jit_lvalue_get_address ( 401 get_random_lvalue (ff, max_depth - 1), 402 get_random_location (ff->f)); 403 404 /* TODO: 405 - comparisons 406 - calls 407 - array lookup 408 - fields 409 - dereferencing */ 410 } 411 return NULL; 412} 413 414 415/* Top-level defns for use by harness. */ 416void 417create_code (gcc_jit_context *ctxt, void *user_data) 418{ 419 fuzzer f; 420 int seed = *(int*)user_data; 421 422 fuzzer_init (&f, ctxt, seed); 423} 424 425static int num_completed_compilations = 0; 426 427void 428verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) 429{ 430 /* We can make no guarantees about whether we built something 431 valid or not, and the result might have an infinite loop, 432 so we can't execute it. 433 434 If we survive to reach here, note the fact for DejaGnu. */ 435 pass ("%s: survived compilation", test); 436 if (result) 437 num_completed_compilations++; 438} 439 440static void 441test_fuzzer (const char *argv0, int seed) 442{ 443 test_jit (argv0, &seed); 444} 445 446int 447main (int argc, char **argv) 448{ 449 int i, seed; 450 const int NUM_ITERATIONS = 2; 451 const int NUM_SEEDS = 100; 452 for (i = 1; i <= NUM_ITERATIONS; i++) 453 { 454 for (seed = 0; seed < NUM_SEEDS ; seed++) 455 { 456 snprintf (test, sizeof (test), 457 "%s iteration %d of %d; seed %d of %d", 458 extract_progname (argv[0]), 459 i, NUM_ITERATIONS, seed, NUM_SEEDS); 460 test_fuzzer (argv[0], seed); 461 } 462 } 463 pass ("%s: survived running all tests", extract_progname (argv[0])); 464 note ("%s: num completed compilations: %d", extract_progname (argv[0]), 465 num_completed_compilations); 466 totals (); 467 468 return 0; 469} 470