vvm/interpreter/
memory.rs

1// Copyright 2015-2020 Parity Technologies (UK) Ltd.
2// This file is part of Tetsy Vapory.
3
4// Tetsy Vapory is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Tetsy Vapory is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Tetsy Vapory.  If not, see <http://www.gnu.org/licenses/>.
16
17use vapory_types::U256;
18use tetsy_vm::ReturnData;
19
20const MAX_RETURN_WASTE_BYTES: usize = 16384;
21
22pub trait Memory {
23	/// Retrieve current size of the memory
24	fn size(&self) -> usize;
25	/// Resize (shrink or expand) the memory to specified size (fills 0)
26	fn resize(&mut self, new_size: usize);
27	/// Resize the memory only if its smaller
28	fn expand(&mut self, new_size: usize);
29	/// Write single byte to memory
30	fn write_byte(&mut self, offset: U256, value: U256);
31	/// Write a word to memory. Does not resize memory!
32	fn write(&mut self, offset: U256, value: U256);
33	/// Read a word from memory
34	fn read(&self, offset: U256) -> U256;
35	/// Write slice of bytes to memory. Does not resize memory!
36	fn write_slice(&mut self, offset: U256, slice: &[u8]);
37	/// Retrieve part of the memory between offset and offset + size
38	fn read_slice(&self, offset: U256, size: U256) -> &[u8];
39	/// Retrieve writeable part of memory
40	fn writeable_slice(&mut self, offset: U256, size: U256) -> &mut[u8];
41	/// Convert memory into return data.
42	fn into_return_data(self, offset: U256, size: U256) -> ReturnData;
43}
44
45/// Checks whether offset and size is valid memory range
46pub fn is_valid_range(off: usize, size: usize)  -> bool {
47	// When size is zero we haven't actually expanded the memory
48	let overflow = off.overflowing_add(size).1;
49	size > 0 && !overflow
50}
51
52impl Memory for Vec<u8> {
53	fn size(&self) -> usize {
54		self.len()
55	}
56
57	fn read_slice(&self, init_off_u: U256, init_size_u: U256) -> &[u8] {
58		let off = init_off_u.low_u64() as usize;
59		let size = init_size_u.low_u64() as usize;
60		if !is_valid_range(off, size) {
61			&self[0..0]
62		} else {
63			&self[off..off+size]
64		}
65	}
66
67	fn read(&self, offset: U256) -> U256 {
68		let off = offset.low_u64() as usize;
69		U256::from(&self[off..off+32])
70	}
71
72	fn writeable_slice(&mut self, offset: U256, size: U256) -> &mut [u8] {
73		let off = offset.low_u64() as usize;
74		let s = size.low_u64() as usize;
75		if !is_valid_range(off, s) {
76			&mut self[0..0]
77		} else {
78			&mut self[off..off+s]
79		}
80	}
81
82	fn write_slice(&mut self, offset: U256, slice: &[u8]) {
83		if !slice.is_empty() {
84			let off = offset.low_u64() as usize;
85			self[off..off+slice.len()].copy_from_slice(slice);
86		}
87	}
88
89	fn write(&mut self, offset: U256, value: U256) {
90		let off = offset.low_u64() as usize;
91		value.to_big_endian(&mut self[off..off+32]);
92	}
93
94	fn write_byte(&mut self, offset: U256, value: U256) {
95		let off = offset.low_u64() as usize;
96		let val = value.low_u64() as u64;
97		self[off] = val as u8;
98	}
99
100	fn resize(&mut self, new_size: usize) {
101		self.resize(new_size, 0);
102	}
103
104	fn expand(&mut self, size: usize) {
105		if size > self.len() {
106			Memory::resize(self, size)
107		}
108	}
109
110	fn into_return_data(mut self, offset: U256, size: U256) -> ReturnData {
111		let mut offset = offset.low_u64() as usize;
112		let size = size.low_u64() as usize;
113
114		if !is_valid_range(offset, size) {
115			return ReturnData::empty();
116		}
117
118		if self.len() - size > MAX_RETURN_WASTE_BYTES {
119			if offset == 0 {
120				self.truncate(size);
121				self.shrink_to_fit();
122			} else {
123				self = self[offset..(offset + size)].to_vec();
124				offset = 0;
125			}
126		}
127		ReturnData::new(self, offset, size)
128	}
129}
130
131#[cfg(test)]
132mod tests {
133	use vapory_types::U256;
134	use super::Memory;
135
136	#[test]
137	fn test_memory_read_and_write() {
138		// given
139		let mem: &mut dyn Memory = &mut vec![];
140		mem.resize(0x80 + 32);
141
142		// when
143		mem.write(U256::from(0x80), U256::from(0xabcdef));
144
145		// then
146		assert_eq!(mem.read(U256::from(0x80)), U256::from(0xabcdef));
147	}
148
149	#[test]
150	fn test_memory_read_and_write_byte() {
151		// given
152		let mem: &mut dyn Memory = &mut vec![];
153		mem.resize(32);
154
155		// when
156		mem.write_byte(U256::from(0x1d), U256::from(0xab));
157		mem.write_byte(U256::from(0x1e), U256::from(0xcd));
158		mem.write_byte(U256::from(0x1f), U256::from(0xef));
159
160		// then
161		assert_eq!(mem.read(U256::from(0x00)), U256::from(0xabcdef));
162	}
163
164	#[test]
165	fn test_memory_read_slice_and_write_slice() {
166		let mem: &mut dyn Memory = &mut vec![];
167		mem.resize(32);
168
169		{
170			let slice = "abcdefghijklmnopqrstuvwxyz012345".as_bytes();
171			mem.write_slice(U256::from(0), slice);
172
173			assert_eq!(mem.read_slice(U256::from(0), U256::from(32)), slice);
174		}
175
176		// write again
177		{
178			let slice = "67890".as_bytes();
179			mem.write_slice(U256::from(0x1), slice);
180
181			assert_eq!(mem.read_slice(U256::from(0), U256::from(7)), "a67890g".as_bytes());
182		}
183
184		// write empty slice out of bounds
185		{
186			let slice = [];
187			mem.write_slice(U256::from(0x1000), &slice);
188			assert_eq!(mem.size(), 32);
189		}
190	}
191}