cranelift: CLIF fuzzer generate jump tables and br_table
This commit is contained in:
@@ -16,6 +16,8 @@ pub struct Config {
|
||||
/// This value does not apply to block0 which takes the function params
|
||||
/// and is thus governed by `signature_params`
|
||||
pub block_signature_params: RangeInclusive<usize>,
|
||||
pub jump_tables_per_function: RangeInclusive<usize>,
|
||||
pub jump_table_entries: RangeInclusive<usize>,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
@@ -28,6 +30,8 @@ impl Default for Config {
|
||||
vars_per_function: 0..=16,
|
||||
blocks_per_function: 0..=16,
|
||||
block_signature_params: 0..=16,
|
||||
jump_tables_per_function: 0..=4,
|
||||
jump_table_entries: 0..=16,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,11 +3,11 @@ use anyhow::Result;
|
||||
use arbitrary::{Arbitrary, Unstructured};
|
||||
use cranelift::codegen::ir::types::*;
|
||||
use cranelift::codegen::ir::{
|
||||
AbiParam, Block, ExternalName, Function, Opcode, Signature, Type, Value,
|
||||
AbiParam, Block, ExternalName, Function, JumpTable, Opcode, Signature, Type, Value,
|
||||
};
|
||||
use cranelift::codegen::isa::CallConv;
|
||||
use cranelift::frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
|
||||
use cranelift::prelude::{EntityRef, InstBuilder, IntCC};
|
||||
use cranelift::prelude::{EntityRef, InstBuilder, IntCC, JumpTableData};
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
type BlockSignature = Vec<Type>;
|
||||
@@ -98,6 +98,7 @@ where
|
||||
config: &'r Config,
|
||||
vars: Vec<(Type, Variable)>,
|
||||
blocks: Vec<(Block, BlockSignature)>,
|
||||
jump_tables: Vec<JumpTable>,
|
||||
}
|
||||
|
||||
impl<'r, 'data> FunctionGenerator<'r, 'data>
|
||||
@@ -110,6 +111,7 @@ where
|
||||
config,
|
||||
vars: vec![],
|
||||
blocks: vec![],
|
||||
jump_tables: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,6 +237,16 @@ where
|
||||
Ok((block, args))
|
||||
}
|
||||
|
||||
/// Valid blocks for jump tables have to have no parameters in the signature, and must also
|
||||
/// not be the first block.
|
||||
fn generate_valid_jumptable_target_blocks(&mut self) -> Vec<Block> {
|
||||
self.blocks[1..]
|
||||
.iter()
|
||||
.filter(|(_, sig)| sig.len() == 0)
|
||||
.map(|(b, _)| *b)
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn generate_values_for_signature<I: Iterator<Item = Type>>(
|
||||
&mut self,
|
||||
builder: &mut FunctionBuilder,
|
||||
@@ -266,6 +278,20 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Generates a br_table into a random block
|
||||
fn generate_br_table(&mut self, builder: &mut FunctionBuilder) -> Result<()> {
|
||||
let _type = *self.u.choose(&[I8, I16, I32, I64][..])?;
|
||||
let var = self.get_variable_of_type(_type)?;
|
||||
let val = builder.use_var(var);
|
||||
|
||||
let valid_blocks = self.generate_valid_jumptable_target_blocks();
|
||||
let default_block = *self.u.choose(&valid_blocks[..])?;
|
||||
|
||||
let jt = *self.u.choose(&self.jump_tables[..])?;
|
||||
builder.ins().br_table(val, default_block, jt);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Generates a brz/brnz into a random block
|
||||
fn generate_br(&mut self, builder: &mut FunctionBuilder) -> Result<()> {
|
||||
let (block, args) = self.generate_target_block(builder)?;
|
||||
@@ -320,6 +346,7 @@ where
|
||||
&[
|
||||
Self::generate_bricmp,
|
||||
Self::generate_br,
|
||||
Self::generate_br_table,
|
||||
Self::generate_jump,
|
||||
Self::generate_return,
|
||||
][..],
|
||||
@@ -338,6 +365,22 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn generate_jumptables(&mut self, builder: &mut FunctionBuilder) -> Result<()> {
|
||||
let valid_blocks = self.generate_valid_jumptable_target_blocks();
|
||||
|
||||
for _ in 0..self.param(&self.config.jump_tables_per_function)? {
|
||||
let mut jt_data = JumpTableData::new();
|
||||
|
||||
for _ in 0..self.param(&self.config.jump_table_entries)? {
|
||||
let block = *self.u.choose(&valid_blocks[..])?;
|
||||
jt_data.push_entry(block);
|
||||
}
|
||||
|
||||
self.jump_tables.push(builder.create_jump_table(jt_data));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Creates a random amount of blocks in this function
|
||||
fn generate_blocks(
|
||||
&mut self,
|
||||
@@ -422,6 +465,9 @@ where
|
||||
|
||||
self.blocks = self.generate_blocks(&mut builder, &sig)?;
|
||||
|
||||
// Function preamble
|
||||
self.generate_jumptables(&mut builder)?;
|
||||
|
||||
// Main instruction generation loop
|
||||
for (i, (block, block_sig)) in self.blocks.clone().iter().enumerate() {
|
||||
let is_block0 = i == 0;
|
||||
|
||||
Reference in New Issue
Block a user