1 /* Fuzz-testing of libgccjit API.
2 Currently this triggers internal compiler errors, typically due to type
11 #define TEST_PROVIDES_MAIN
16 gcc_jit_context
*ctxt
;
24 gcc_jit_lvalue
**globals
;
27 gcc_jit_function
**funcs
;
32 fuzzer_init (fuzzer
*f
, gcc_jit_context
*ctxt
, unsigned int seed
);
35 fuzzer_randrange (fuzzer
*f
, int min
, int max
);
37 static gcc_jit_location
*
38 get_random_location (fuzzer
*f
);
41 get_random_type (fuzzer
*f
);
44 make_random_type (fuzzer
*f
);
46 static gcc_jit_lvalue
*
47 make_random_global (fuzzer
*f
);
49 static gcc_jit_function
*
50 make_random_function (fuzzer
*f
);
52 typedef struct function_fuzzer
57 gcc_jit_param
**params
;
62 gcc_jit_lvalue
**locals
;
69 function_fuzzer_add_stmt (function_fuzzer
*ff
);
71 static gcc_jit_lvalue
*
72 get_random_lvalue (function_fuzzer
*ff
, int max_depth
);
74 static gcc_jit_rvalue
*
75 get_random_rvalue (function_fuzzer
*ff
, int max_depth
);
80 fuzzer_init (fuzzer
*f
, gcc_jit_context
*ctxt
, unsigned int seed
)
83 memset (f
, 0, sizeof (*f
));
87 int num_types
= fuzzer_randrange (f
, 5, 10);
88 f
->types
= malloc (num_types
* sizeof (gcc_jit_type
*));
90 int num_funcs
= fuzzer_randrange (f
, 3, 5);
91 f
->funcs
= malloc (num_funcs
* sizeof (gcc_jit_function
*));
93 int num_globals
= fuzzer_randrange (f
, 5, 10);
94 f
->globals
= malloc (num_globals
* sizeof (gcc_jit_lvalue
*));
96 for (i
= 0; i
< num_types
; i
++)
98 gcc_jit_type
*type
= make_random_type (f
);
100 f
->types
[f
->num_types
++] = type
;
103 for (i
= 0; i
< num_globals
; i
++)
104 f
->globals
[f
->num_globals
++] = make_random_global (f
);
106 for (i
= 0; i
< num_funcs
; i
++)
107 f
->funcs
[f
->num_funcs
++] = make_random_function (f
);
109 /* Now clean out f. */
115 /* Get random int in inclusive range [min, max]. */
117 static int fuzzer_randrange (fuzzer
*f
, int min
, int max
)
120 int i
= rand_r (&f
->seed
);
121 int result
= (i
% (max
+ 1 - min
)) + min
;
122 assert (result
>= min
);
123 assert (result
<= max
);
127 static gcc_jit_location
*
128 get_random_location (fuzzer
*f
)
130 const char *filename
= NULL
;
132 if (fuzzer_randrange (f
, 0, 1))
135 switch (fuzzer_randrange (f
, 1, 2))
145 return gcc_jit_context_new_location (f
->ctxt
,
147 fuzzer_randrange (f
, 1, 1000),
148 fuzzer_randrange (f
, 1, 1000));
151 const enum gcc_jit_types types
[] = {
154 GCC_JIT_TYPE_VOID_PTR
,
157 GCC_JIT_TYPE_SIGNED_CHAR
,
158 GCC_JIT_TYPE_UNSIGNED_CHAR
,
161 GCC_JIT_TYPE_UNSIGNED_SHORT
,
164 GCC_JIT_TYPE_UNSIGNED_INT
,
167 GCC_JIT_TYPE_UNSIGNED_LONG
,
169 GCC_JIT_TYPE_LONG_LONG
,
170 GCC_JIT_TYPE_UNSIGNED_LONG_LONG
,
174 GCC_JIT_TYPE_LONG_DOUBLE
,
176 GCC_JIT_TYPE_CONST_CHAR_PTR
,
180 GCC_JIT_TYPE_FILE_PTR
182 #define NUM_TYPES (sizeof(types)/sizeof(types[0]))
184 static gcc_jit_type
*
185 get_random_type (fuzzer
*f
)
187 int i
= fuzzer_randrange (f
, 0, (NUM_TYPES
- 1) + f
->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
];
195 static gcc_jit_type
*
196 make_random_type (fuzzer
*f
)
198 switch (fuzzer_randrange (f
, 0, 5))
201 return gcc_jit_type_get_pointer (get_random_type (f
));
203 return gcc_jit_type_get_const (get_random_type (f
));
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
*));
211 for (i
= 0; i
< num_fields
; i
++)
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
),
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
),
229 return gcc_jit_struct_as_type (struct_
);
234 static gcc_jit_lvalue
*
235 make_random_global (fuzzer
*f
)
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
,
246 static gcc_jit_function
*
247 make_random_function (fuzzer
*f
)
250 sprintf (func_name
, "fn%i", f
->num_funcs
);
252 function_fuzzer
*ff
= malloc (sizeof (function_fuzzer
));
253 memset (ff
, 0, sizeof (*ff
));
257 ff
->num_params
= fuzzer_randrange (f
, 0, 10);
258 ff
->params
= malloc (ff
->num_params
* sizeof (gcc_jit_param
*));
260 for (i
= 0; i
< ff
->num_params
; i
++)
262 char param_name
[256];
263 sprintf (param_name
, "param%i", i
);
265 gcc_jit_context_new_param (f
->ctxt
,
266 get_random_location (f
),
271 enum gcc_jit_function_kind kind
=
272 ((enum gcc_jit_function_kind
)
273 fuzzer_randrange (f
, 0, GCC_JIT_FUNCTION_IMPORTED
));
276 gcc_jit_context_new_function (
278 get_random_location (f
),
284 fuzzer_randrange (f
, 0, 1));
285 ff
->block
= gcc_jit_function_new_block (ff
->fn
, NULL
);
288 if (kind
!= GCC_JIT_FUNCTION_IMPORTED
)
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
++)
294 char local_name
[256];
295 sprintf (local_name
, "local%i", i
);
297 gcc_jit_function_new_local (ff
->fn
,
298 get_random_location (f
),
303 /* TODO: use locals. */
305 if (kind
!= GCC_JIT_FUNCTION_IMPORTED
)
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
);
313 gcc_jit_block_end_with_return (ff
->block
, NULL
, get_random_rvalue (ff
, 3));
316 gcc_jit_function
*result
= ff
->fn
;
325 /* function_fuzzer defns. */
327 static void function_fuzzer_add_stmt (function_fuzzer
*ff
)
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 */
340 static gcc_jit_lvalue
*get_random_lvalue (function_fuzzer
*ff
, int max_depth
)
342 int choice
= fuzzer_randrange (ff
->f
, 0,
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
;
350 if (choice
< ff
->num_locals
)
351 return ff
->locals
[choice
];
352 choice
-= ff
->num_locals
;
354 assert (choice
< ff
->f
->num_globals
);
355 return ff
->f
->globals
[choice
];
358 static gcc_jit_rvalue
*get_random_rvalue (function_fuzzer
*ff
, int max_depth
)
360 int use_lvalue
= fuzzer_randrange (ff
->f
, 0, 1);
362 return gcc_jit_lvalue_as_rvalue (get_random_lvalue (ff
, max_depth
));
364 int choice
= fuzzer_randrange (ff
->f
, 0, 1);
370 return gcc_jit_context_new_string_literal (ff
->f
->ctxt
, "hello");
372 return gcc_jit_context_new_rvalue_from_int (
374 get_random_type (ff
->f
),
375 fuzzer_randrange (ff
->f
, 0, INT_MAX
));
377 return gcc_jit_context_new_rvalue_from_double (
379 get_random_type (ff
->f
),
380 ((double)fuzzer_randrange (ff
->f
, 0, INT_MAX
))
381 / (double)fuzzer_randrange (ff
->f
, 0, INT_MAX
));
383 return gcc_jit_context_new_unary_op (
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));
391 return gcc_jit_context_new_binary_op (
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));
400 return gcc_jit_lvalue_get_address (
401 get_random_lvalue (ff
, max_depth
- 1),
402 get_random_location (ff
->f
));
415 /* Top-level defns for use by harness. */
417 create_code (gcc_jit_context
*ctxt
, void *user_data
)
420 int seed
= *(int*)user_data
;
422 fuzzer_init (&f
, ctxt
, seed
);
425 static int num_completed_compilations
= 0;
428 verify_code (gcc_jit_context
*ctxt
, gcc_jit_result
*result
)
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.
434 If we survive to reach here, note the fact for DejaGnu. */
435 pass ("%s: survived compilation", test
);
437 num_completed_compilations
++;
441 test_fuzzer (const char *argv0
, int seed
)
443 test_jit (argv0
, &seed
);
447 main (int argc
, char **argv
)
450 const int NUM_ITERATIONS
= 2;
451 const int NUM_SEEDS
= 100;
452 for (i
= 1; i
<= NUM_ITERATIONS
; i
++)
454 for (seed
= 0; seed
< NUM_SEEDS
; seed
++)
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
);
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
);