#![recursion_limit = "256"]
extern crate proc_macro;
extern crate proc_macro2;
extern crate syn;
#[macro_use]
extern crate log;
use quote::quote;
use proc_macro2::TokenStream;
use syn::{parse_macro_input, DeriveInput};
mod attr;
mod fuzzerobject;
mod new_fuzzed;
mod serialize;
mod utils;
use crate::fuzzerobject::*;
use crate::new_fuzzed::*;
use crate::serialize::binary_serialize_helper;
use syn::{Fields, Data};
use syn::spanned::Spanned;
use quote::quote_spanned;
#[proc_macro_derive(NewFuzzed, attributes(weight, fuzzer, bitfield))]
pub fn new_fuzzed(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let tokens = new_fuzzed_helper(input);
tokens
}
#[proc_macro_derive(
BinarySerialize,
attributes(bitfield, byteorder, inner_member_serialized_size, serialized_size)
)]
pub fn binary_serialize(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
binary_serialize_helper(input)
}
#[proc_macro_derive(Mutatable, attributes(fuzzer, bitfield))]
pub fn mutatable_helper(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
let imp = gen_mutate_impl(&name, &input.data);
let expanded = quote! {
impl #impl_generics ::lain::traits::Mutatable for #name #ty_generics #where_clause {
#imp
}
};
proc_macro::TokenStream::from(expanded)
}
#[proc_macro_derive(VariableSizeObject)]
pub fn variable_size_object_helper(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let imp: TokenStream;
match input.data {
Data::Enum(ref data) => {
let mut simple_variants = true;
for variant in &data.variants {
match variant.fields {
Fields::Unit => {
continue;
}
_ => {
simple_variants = false;
}
}
}
imp = if simple_variants {
quote!{false}
} else {
quote!{true}
};
}
Data::Struct(ref data) => {
if let Fields::Named(ref fields) = data.fields {
if fields.named.len() == 0 {
imp = quote!{false};
} else {
let mut tokens = quote!{false};
for field in fields.named.iter() {
let ty = &field.ty;
tokens.extend(quote_spanned!{ field.span() =>
|| <#ty>::is_variable_size()
});
}
imp = tokens;
}
} else {
panic!("Need to add support for unnamed struct fields");
}
}
_ => panic!("Non-enum/struct data types are not supported"),
}
let name = input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
let expanded = quote! {
impl #impl_generics ::lain::traits::VariableSizeObject for #name #ty_generics #where_clause {
fn is_variable_size() -> bool {
#imp
}
}
};
proc_macro::TokenStream::from(expanded)
}
#[proc_macro_derive(PostFuzzerIteration)]
pub fn post_fuzzer_iteration(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
let on_success = get_post_fuzzer_iteration_impls(&name, &input.data);
let expanded = quote! {
impl #impl_generics ::lain::traits::PostFuzzerIteration for #name #ty_generics #where_clause {
fn on_success_for_fields(&self) {
#on_success
}
}
};
debug!("{}", expanded);
proc_macro::TokenStream::from(expanded)
}
#[proc_macro_derive(FixupChildren)]
pub fn post_mutation(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
let post_mutation = get_post_mutation_impl(&name, &input.data);
let expanded = quote! {
impl #impl_generics ::lain::traits::FixupChildren for #name #ty_generics #where_clause {
fn fixup_children<R: ::lain::rand::Rng>(&mut self, mutator: &mut Mutator<R>) {
#post_mutation
}
}
};
debug!("{}", expanded);
proc_macro::TokenStream::from(expanded)
}
#[proc_macro_derive(FuzzerObject, attributes(fuzzer, bitfield, weight))]
pub fn fuzzer_object(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let mut base_token_stream = TokenStream::new();
base_token_stream.extend(TokenStream::from(new_fuzzed_helper(input.clone())));
base_token_stream.extend(TokenStream::from(mutatable_helper(input.clone())));
base_token_stream.extend(TokenStream::from(post_fuzzer_iteration(input.clone())));
base_token_stream.extend(TokenStream::from(post_mutation(input.clone())));
base_token_stream.extend(TokenStream::from(variable_size_object_helper(input.clone())));
debug!("{}", base_token_stream);
proc_macro::TokenStream::from(base_token_stream)
}
#[proc_macro_derive(ToPrimitiveU8)]
pub fn to_primitive_u8(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
to_primitive_of_type(input, quote! {u8})
}
#[proc_macro_derive(ToPrimitiveU16)]
pub fn to_primitive_u16(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
to_primitive_of_type(input, quote! {u16})
}
#[proc_macro_derive(ToPrimitiveU32)]
pub fn to_primitive_u32(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
to_primitive_of_type(input, quote! {u32})
}
#[proc_macro_derive(ToPrimitiveU64)]
pub fn to_primitive_u64(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
to_primitive_of_type(input, quote! {u64})
}
fn to_primitive_of_type(
input: proc_macro::TokenStream,
ty: proc_macro2::TokenStream,
) -> proc_macro::TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
let expanded = quote! {
impl #impl_generics ::lain::traits::ToPrimitive<#ty> for #name #ty_generics #where_clause {
fn to_primitive(&self) -> #ty {
*self as #ty
}
}
};
debug!("{}", expanded);
proc_macro::TokenStream::from(expanded)
}