2016-01-02 18:27:06 -05:00
|
|
|
#![feature(zero_one)]
|
|
|
|
|
|
|
|
extern crate rand;
|
|
|
|
|
2015-12-30 17:14:48 -05:00
|
|
|
extern crate alchemy;
|
2016-01-02 18:27:06 -05:00
|
|
|
extern crate sigils;
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-01-03 03:22:21 -05:00
|
|
|
use std::thread::{Builder, JoinHandle};
|
2016-01-02 18:27:06 -05:00
|
|
|
|
2016-01-06 23:37:18 -05:00
|
|
|
use alchemy::{U16_BYTES, U32_BYTES, U64_BYTES};
|
|
|
|
use alchemy::{I16_BYTES, I32_BYTES, I64_BYTES};
|
|
|
|
use alchemy::{USIZE_BYTES, ISIZE_BYTES};
|
|
|
|
use alchemy::{F32_BYTES, F64_BYTES};
|
2016-01-02 18:27:06 -05:00
|
|
|
|
|
|
|
|
2016-01-03 03:22:21 -05:00
|
|
|
const EXHAUSTIVE_RUNS: u64 = 10000u64;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
macro_rules! create_thread
|
|
|
|
{
|
|
|
|
($thread_name: expr, $func_name: ident) =>
|
|
|
|
{
|
|
|
|
{
|
|
|
|
let builder: Builder;
|
|
|
|
|
|
|
|
builder = Builder::new().name($thread_name.to_string());
|
|
|
|
match builder.spawn($func_name)
|
|
|
|
{
|
|
|
|
Ok(handle) =>
|
|
|
|
{
|
|
|
|
handle
|
|
|
|
}
|
|
|
|
|
|
|
|
Err(_) =>
|
|
|
|
{
|
|
|
|
panic!("Error spawning thread: {}.", $thread_name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
macro_rules! full_check_impl
|
|
|
|
{
|
|
|
|
($T: ident, $read_func: ident, $write_func: ident, $numBytes: expr) =>
|
|
|
|
{
|
|
|
|
{
|
|
|
|
use rand::ThreadRng;
|
|
|
|
use rand::distributions::{IndependentSample, Range};
|
2016-01-05 23:42:08 -05:00
|
|
|
use alchemy::{Converter, BigEndian, LittleEndian};
|
2016-01-03 03:22:21 -05:00
|
|
|
|
|
|
|
let range: Range<$T>;
|
|
|
|
let mut rng: ThreadRng;
|
|
|
|
|
|
|
|
rng = rand::thread_rng();
|
|
|
|
range = Range::new(std::$T::MIN, std::$T::MAX);
|
|
|
|
for _ in 0..EXHAUSTIVE_RUNS
|
|
|
|
{
|
|
|
|
let val: $T;
|
|
|
|
let final_big_val: $T;
|
|
|
|
let final_little_val: $T;
|
|
|
|
let mut buffer: [u8; $numBytes];
|
|
|
|
|
|
|
|
buffer = [0u8; $numBytes];
|
|
|
|
val = range.ind_sample(&mut rng);
|
|
|
|
|
|
|
|
BigEndian::$write_func(&mut buffer, val);
|
|
|
|
final_big_val = BigEndian::$read_func(&buffer);
|
|
|
|
if final_big_val != val
|
|
|
|
{
|
|
|
|
panic!(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
LittleEndian::$write_func(&mut buffer, val);
|
|
|
|
final_little_val = LittleEndian::$read_func(&buffer);
|
|
|
|
if final_little_val != val
|
|
|
|
{
|
|
|
|
panic!(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///
|
|
|
|
macro_rules! full_check
|
|
|
|
{
|
|
|
|
($func_name: ident, $T: ident, $read_func: ident, $write_func: ident) =>
|
|
|
|
{
|
|
|
|
fn $func_name() -> bool
|
|
|
|
{
|
|
|
|
full_check_impl!($T, $read_func, $write_func, $T::BYTES)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
($func_name: ident, $T: ident,
|
|
|
|
$read_func: ident, $write_func: ident, $numBytes: expr) =>
|
|
|
|
{
|
|
|
|
fn $func_name() -> bool
|
|
|
|
{
|
|
|
|
full_check_impl!($T, $read_func, $write_func, $numBytes)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2016-01-02 18:27:06 -05:00
|
|
|
/// This should only be called by the macro below.
|
|
|
|
macro_rules! overflow_impl
|
|
|
|
{
|
|
|
|
($numBytes: expr, $T: ident,
|
|
|
|
$read_func: ident, $write_func: ident) =>
|
|
|
|
{
|
2016-01-05 23:42:08 -05:00
|
|
|
use alchemy::{Converter, BigEndian, LittleEndian};
|
2016-01-02 18:27:06 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic]
|
|
|
|
fn read_big_endian()
|
|
|
|
{
|
2016-01-03 03:22:21 -05:00
|
|
|
let buffer: [u8; $numBytes - 1];
|
2016-01-02 18:27:06 -05:00
|
|
|
|
2016-01-03 03:22:21 -05:00
|
|
|
buffer = [0u8; $numBytes - 1];
|
2016-01-02 18:27:06 -05:00
|
|
|
BigEndian::$read_func(&buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic]
|
|
|
|
fn read_little_endian()
|
|
|
|
{
|
2016-01-03 03:22:21 -05:00
|
|
|
let buffer: [u8; $numBytes - 1];
|
2016-01-02 18:27:06 -05:00
|
|
|
|
2016-01-03 03:22:21 -05:00
|
|
|
buffer = [0u8; $numBytes - 1];
|
2016-01-02 18:27:06 -05:00
|
|
|
LittleEndian::$read_func(&buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic]
|
|
|
|
fn write_big_endian()
|
|
|
|
{
|
2016-01-03 03:22:21 -05:00
|
|
|
let mut buffer: [u8; $numBytes - 1];
|
2016-01-02 18:27:06 -05:00
|
|
|
|
2016-01-03 03:22:21 -05:00
|
|
|
buffer = [0u8; $numBytes - 1];
|
2016-01-02 18:27:06 -05:00
|
|
|
BigEndian::$write_func(&mut buffer, $T::zero());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic]
|
|
|
|
fn write_little_endian()
|
|
|
|
{
|
2016-01-03 03:22:21 -05:00
|
|
|
let mut buffer: [u8; $numBytes - 1];
|
2016-01-02 18:27:06 -05:00
|
|
|
|
2016-01-03 03:22:21 -05:00
|
|
|
buffer = [0u8; $numBytes - 1];
|
2016-01-02 23:16:39 -05:00
|
|
|
LittleEndian::$write_func(&mut buffer, $T::zero());
|
2016-01-02 18:27:06 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/// This macro tries to test for buffer overflow happening.
|
|
|
|
macro_rules! test_buffer_overflow
|
|
|
|
{
|
|
|
|
($mod_name: ident, $T: ident,
|
2016-01-06 23:37:18 -05:00
|
|
|
$read_func: ident, $write_func: ident, $numBytes: ident) =>
|
2016-01-02 18:27:06 -05:00
|
|
|
{
|
|
|
|
mod $mod_name
|
|
|
|
{
|
2016-01-06 23:37:18 -05:00
|
|
|
use alchemy::$numBytes;
|
|
|
|
use std::num::Zero;
|
2016-01-02 18:27:06 -05:00
|
|
|
|
|
|
|
overflow_impl!($numBytes, $T, $read_func, $write_func);
|
|
|
|
}
|
2016-01-06 23:37:18 -05:00
|
|
|
}
|
2016-01-02 18:27:06 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Test the different data types for buffer overflow.
|
2016-01-06 23:37:18 -05:00
|
|
|
test_buffer_overflow!(overflow_u16, u16, bytes_to_u16, u16_to_bytes, U16_BYTES);
|
|
|
|
test_buffer_overflow!(overflow_u32, u32, bytes_to_u32, u32_to_bytes, U32_BYTES);
|
|
|
|
test_buffer_overflow!(overflow_u64, u64, bytes_to_u64, u64_to_bytes, U64_BYTES);
|
2016-01-02 23:16:39 -05:00
|
|
|
test_buffer_overflow!(overflow_usize, usize,
|
2016-01-06 23:37:18 -05:00
|
|
|
bytes_to_usize, usize_to_bytes, U8_BYTES);
|
2016-01-02 18:27:06 -05:00
|
|
|
|
2016-01-06 23:37:18 -05:00
|
|
|
test_buffer_overflow!(overflow_i16, i16, bytes_to_i16, i16_to_bytes, I16_BYTES);
|
|
|
|
test_buffer_overflow!(overflow_i32, i32, bytes_to_i32, i32_to_bytes, I32_BYTES);
|
|
|
|
test_buffer_overflow!(overflow_i64, i64, bytes_to_i64, i64_to_bytes, I64_BYTES);
|
2016-01-02 23:16:39 -05:00
|
|
|
test_buffer_overflow!(overflow_isize, isize,
|
2016-01-06 23:37:18 -05:00
|
|
|
bytes_to_isize, isize_to_bytes, U8_BYTES);
|
2016-01-02 18:27:06 -05:00
|
|
|
|
2016-01-06 23:37:18 -05:00
|
|
|
test_buffer_overflow!(overflow_f32, f32, bytes_to_f32, f32_to_bytes, F32_BYTES);
|
|
|
|
test_buffer_overflow!(overflow_f64, f64, bytes_to_f64, f64_to_bytes, F64_BYTES);
|
2016-01-03 03:22:21 -05:00
|
|
|
|
|
|
|
// Create the exhaustive check functions for the integer types.
|
2016-01-06 23:37:18 -05:00
|
|
|
full_check!(check_u16, u16, bytes_to_u16, u16_to_bytes, U16_BYTES);
|
|
|
|
full_check!(check_u32, u32, bytes_to_u32, u32_to_bytes, U32_BYTES);
|
|
|
|
full_check!(check_u64, u64, bytes_to_u64, u64_to_bytes, U64_BYTES);
|
|
|
|
full_check!(check_usize, usize, bytes_to_usize, usize_to_bytes, USIZE_BYTES);
|
|
|
|
|
|
|
|
full_check!(check_i16, i16, bytes_to_i16, i16_to_bytes, I16_BYTES);
|
|
|
|
full_check!(check_i32, i32, bytes_to_i32, i32_to_bytes, I32_BYTES);
|
|
|
|
full_check!(check_i64, i64, bytes_to_i64, i64_to_bytes, I64_BYTES);
|
|
|
|
full_check!(check_isize, isize, bytes_to_isize, isize_to_bytes, ISIZE_BYTES);
|
|
|
|
|
|
|
|
full_check!(check_f32, f32, bytes_to_f32, f32_to_bytes, F32_BYTES);
|
|
|
|
full_check!(check_f64, f64, bytes_to_f64, f64_to_bytes, F64_BYTES);
|
2016-01-03 03:22:21 -05:00
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn exhaustive_check()
|
|
|
|
{
|
|
|
|
let mut threads: Vec<JoinHandle<bool>>;
|
|
|
|
|
|
|
|
threads = Vec::new();
|
|
|
|
threads.push(create_thread!("u16", check_u16));
|
|
|
|
threads.push(create_thread!("u32", check_u32));
|
|
|
|
threads.push(create_thread!("u64", check_u64));
|
|
|
|
threads.push(create_thread!("usize", check_usize));
|
|
|
|
threads.push(create_thread!("i16", check_i16));
|
|
|
|
threads.push(create_thread!("i32", check_i32));
|
|
|
|
threads.push(create_thread!("i64", check_i64));
|
|
|
|
threads.push(create_thread!("isize", check_isize));
|
|
|
|
threads.push(create_thread!("f32", check_f32));
|
|
|
|
threads.push(create_thread!("f64", check_f64));
|
|
|
|
|
|
|
|
for handle in threads
|
|
|
|
{
|
|
|
|
let mut name: String;
|
|
|
|
|
|
|
|
name = String::new();
|
|
|
|
name.push_str(handle.thread().name().unwrap());
|
|
|
|
match handle.join()
|
|
|
|
{
|
|
|
|
Ok(result) =>
|
|
|
|
{
|
|
|
|
println!("{}: {}", name, result);
|
|
|
|
}
|
|
|
|
|
|
|
|
Err(_) =>
|
|
|
|
{
|
|
|
|
panic!("{}", name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|