1 use std::collections::HashMap; 2 use std::ops::RangeInclusive; 3 4 /// Holds the range of acceptable values to use during the generation of testcases 5 pub struct Config { 6 /// Maximum allowed test case inputs. 7 /// We build test case inputs from the rest of the bytes that the fuzzer provides us 8 /// so we allow the fuzzer to control this by feeding us more or less bytes. 9 /// The upper bound here is to prevent too many inputs that cause long test times 10 pub max_test_case_inputs: usize, 11 // Number of functions that we generate per testcase 12 pub testcase_funcs: RangeInclusive<usize>, 13 pub signature_params: RangeInclusive<usize>, 14 pub signature_rets: RangeInclusive<usize>, 15 pub instructions_per_block: RangeInclusive<usize>, 16 /// Number of variables that we allocate per function 17 /// This value does not include the signature params 18 pub vars_per_function: RangeInclusive<usize>, 19 /// Number of blocks that we generate per function. 20 /// This value does not include the entry block 21 pub blocks_per_function: RangeInclusive<usize>, 22 /// Number of params a block should take 23 /// This value does not apply to block0 which takes the function params 24 /// and is thus governed by `signature_params` 25 pub block_signature_params: RangeInclusive<usize>, 26 /// Max number of jump tables entries to generate 27 pub jump_table_entries: RangeInclusive<usize>, 28 29 /// The Switch API specializes either individual blocks or contiguous ranges. 30 /// In `switch_cases` we decide to produce either a single block or a range. 31 /// The size of the range is controlled by `switch_max_range_size`. 32 pub switch_cases: RangeInclusive<usize>, 33 pub switch_max_range_size: RangeInclusive<usize>, 34 35 /// Stack slots. 36 /// The combination of these two determines stack usage per function 37 pub static_stack_slots_per_function: RangeInclusive<usize>, 38 /// Size in bytes 39 pub static_stack_slot_size: RangeInclusive<usize>, 40 /// Stack slot alignment as a power of 2 41 pub stack_slot_alignment_log2: RangeInclusive<usize>, 42 /// Allowed stack probe sizes 43 pub stack_probe_size_log2: RangeInclusive<usize>, 44 45 /// Determines how often we generate a backwards branch 46 /// Backwards branches are prone to infinite loops, and thus cause timeouts. 47 pub backwards_branch_ratio: (usize, usize), 48 49 /// How often should we allow integer division by zero traps. 50 /// 51 /// Some instructions such as Srem and Udiv can cause a `int_divz` trap 52 /// under some inputs. We almost always insert a sequence of instructions 53 /// that avoids these issues. However we can allow some `int_divz` traps 54 /// by controlling this config. 55 pub allowed_int_divz_ratio: (usize, usize), 56 57 /// How often should we allow fcvt related traps. 58 /// 59 /// `Fcvt*` instructions fail under some inputs, most commonly NaN's. 60 /// We insert a checking sequence to guarantee that those inputs never make 61 /// it to the instruction, but sometimes we want to allow them. 62 pub allowed_fcvt_traps_ratio: (usize, usize), 63 64 /// Some flags really impact compile performance, we still want to test 65 /// them, but probably at a lower rate, so that overall execution time isn't 66 /// impacted as much 67 pub compile_flag_ratio: HashMap<&'static str, (usize, usize)>, 68 69 /// Range of values for the padding between basic blocks. Larger values will 70 /// generate larger functions. 71 pub bb_padding_log2_size: RangeInclusive<usize>, 72 } 73 74 impl Default for Config { default() -> Self75 fn default() -> Self { 76 Config { 77 max_test_case_inputs: 100, 78 testcase_funcs: 1..=8, 79 signature_params: 0..=16, 80 signature_rets: 0..=16, 81 instructions_per_block: 0..=64, 82 vars_per_function: 0..=16, 83 blocks_per_function: 0..=16, 84 block_signature_params: 0..=16, 85 jump_table_entries: 0..=16, 86 switch_cases: 0..=64, 87 // Ranges smaller than 2 don't make sense. 88 switch_max_range_size: 2..=32, 89 static_stack_slots_per_function: 0..=8, 90 static_stack_slot_size: 0..=128, 91 stack_slot_alignment_log2: 0..=10, 92 // We need the mix of sizes that allows us to: 93 // * not generates any stack probes 94 // * generate unrolled stack probes 95 // * generate loop stack probes 96 // 97 // This depends on the total amount of stack space that we have for this function 98 // (controlled by `static_stack_slots_per_function` and `static_stack_slot_size`) 99 // 100 // 1<<6 = 64 and 1<<14 = 16384 101 // 102 // This range allows us to generate all 3 cases within the current allowed 103 // stack size range. 104 stack_probe_size_log2: 6..=14, 105 // 0.1% allows us to explore this, while not causing enough timeouts to significantly 106 // impact execs/s 107 backwards_branch_ratio: (1, 1000), 108 allowed_int_divz_ratio: (1, 1_000_000), 109 allowed_fcvt_traps_ratio: (1, 1_000_000), 110 compile_flag_ratio: [("regalloc_checker", (1usize, 1000))].into_iter().collect(), 111 // Generate up to 4KiB of padding between basic blocks. Although we only 112 // explicitly generate up to 16 blocks, after SSA construction we can 113 // end up with way more blocks than that (Seeing 400 blocks is not uncommon). 114 // At 4KiB we end up at around 1.5MiB of padding per function, which seems reasonable. 115 bb_padding_log2_size: 0..=12, 116 } 117 } 118 } 119