1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
use crate::FuzzTargetImpl;
use anyhow::{bail, Result};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use diem_proptest_helpers::ValueGenerator;
use move_core_types::value::MoveTypeLayout;
use move_vm_types::values::{prop::layout_and_value_strategy, Value};
use std::io::Cursor;
#[derive(Clone, Debug, Default)]
pub struct ValueTarget;
impl FuzzTargetImpl for ValueTarget {
fn description(&self) -> &'static str {
"VM values + types (custom deserializer)"
}
fn generate(&self, _idx: usize, gen: &mut ValueGenerator) -> Option<Vec<u8>> {
let (layout, value) = gen.generate(layout_and_value_strategy());
let layout_blob = bcs::to_bytes(&layout).unwrap();
let value_blob = value.simple_serialize(&layout).expect("must serialize");
let mut blob = vec![];
blob.write_u64::<BigEndian>(layout_blob.len() as u64)
.expect("writing should work");
blob.extend_from_slice(&layout_blob);
blob.extend_from_slice(&value_blob);
Some(blob)
}
fn fuzz(&self, data: &[u8]) {
let _ = deserialize(data);
}
}
fn is_valid_layout(layout: &MoveTypeLayout) -> bool {
use MoveTypeLayout as L;
match layout {
L::Bool | L::U8 | L::U64 | L::U128 | L::Address | L::Signer => true,
L::Vector(layout) => is_valid_layout(layout),
L::Struct(struct_layout) => {
if struct_layout.fields().is_empty() {
return false;
}
struct_layout.fields().iter().all(is_valid_layout)
}
}
}
fn deserialize(data: &[u8]) -> Result<()> {
let mut data = Cursor::new(data);
let layout_len = data.read_u64::<BigEndian>()? as usize;
let position = data.position() as usize;
let data = &data.into_inner()[position..];
if data.len() < layout_len {
bail!("too little data");
}
let layout_data = &data[..layout_len];
let value_data = &data[layout_len..];
let layout: MoveTypeLayout = bcs::from_bytes(layout_data)?;
if !is_valid_layout(&layout) {
bail!("bad layout")
}
let _ = Value::simple_deserialize(value_data, &layout);
Ok(())
}