Fixing memory calculations overflows
This commit is contained in:
parent
e0f3f7adcc
commit
24777cc569
@ -92,6 +92,13 @@ trait Memory {
|
|||||||
fn writeable_slice(&mut self, offset: U256, size: U256) -> &mut[u8];
|
fn writeable_slice(&mut self, offset: U256, size: U256) -> &mut[u8];
|
||||||
fn dump(&self);
|
fn dump(&self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_valid_range(off: usize, size: usize) -> bool {
|
||||||
|
// When size is zero we haven't actually expanded the memory
|
||||||
|
let (_a, overflow) = off.overflowing_add(size);
|
||||||
|
size > 0 && !overflow
|
||||||
|
}
|
||||||
|
|
||||||
impl Memory for Vec<u8> {
|
impl Memory for Vec<u8> {
|
||||||
fn dump(&self) {
|
fn dump(&self) {
|
||||||
println!("MemoryDump:");
|
println!("MemoryDump:");
|
||||||
@ -106,13 +113,12 @@ impl Memory for Vec<u8> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn read_slice(&self, init_off_u: U256, init_size_u: U256) -> &[u8] {
|
fn read_slice(&self, init_off_u: U256, init_size_u: U256) -> &[u8] {
|
||||||
let init_off = init_off_u.low_u64() as usize;
|
let off = init_off_u.low_u64() as usize;
|
||||||
let init_size = init_size_u.low_u64() as usize;
|
let size = init_size_u.low_u64() as usize;
|
||||||
// When size is zero we haven't actually expanded the memory
|
if !is_valid_range(off, size) {
|
||||||
if init_size == 0 {
|
|
||||||
&self[0..0]
|
&self[0..0]
|
||||||
} else {
|
} else {
|
||||||
&self[init_off..init_off + init_size]
|
&self[off..off+size]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,8 +130,7 @@ impl Memory for Vec<u8> {
|
|||||||
fn writeable_slice(&mut self, offset: U256, size: U256) -> &mut [u8] {
|
fn writeable_slice(&mut self, offset: U256, size: U256) -> &mut [u8] {
|
||||||
let off = offset.low_u64() as usize;
|
let off = offset.low_u64() as usize;
|
||||||
let s = size.low_u64() as usize;
|
let s = size.low_u64() as usize;
|
||||||
|
if !is_valid_range(off, s) {
|
||||||
if s == 0 {
|
|
||||||
&mut self[0..0]
|
&mut self[0..0]
|
||||||
} else {
|
} else {
|
||||||
&mut self[off..off+s]
|
&mut self[off..off+s]
|
||||||
@ -323,9 +328,14 @@ impl Interpreter {
|
|||||||
InstructionCost::GasMem(default_gas, self.mem_needed(stack.peek(0), stack.peek(1)))
|
InstructionCost::GasMem(default_gas, self.mem_needed(stack.peek(0), stack.peek(1)))
|
||||||
},
|
},
|
||||||
instructions::SHA3 => {
|
instructions::SHA3 => {
|
||||||
let words = add_u256_usize(stack.peek(1), 31) >> 5;
|
match add_u256_usize(stack.peek(1), 31) {
|
||||||
|
(_w, true) => InstructionCost::GasMem(U256::zero(), RequiredMem::OutOfMemory),
|
||||||
|
(w, false) => {
|
||||||
|
let words = w >> 5;
|
||||||
let gas = U256::from(schedule.sha3_gas) + (U256::from(schedule.sha3_word_gas) * words);
|
let gas = U256::from(schedule.sha3_gas) + (U256::from(schedule.sha3_word_gas) * words);
|
||||||
InstructionCost::GasMem(gas, self.mem_needed(stack.peek(0), stack.peek(1)))
|
InstructionCost::GasMem(gas, self.mem_needed(stack.peek(0), stack.peek(1)))
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
instructions::CALLDATACOPY => {
|
instructions::CALLDATACOPY => {
|
||||||
InstructionCost::GasMemCopy(default_gas, self.mem_needed(stack.peek(0), stack.peek(2)), stack.peek(2).clone())
|
InstructionCost::GasMemCopy(default_gas, self.mem_needed(stack.peek(0), stack.peek(2)), stack.peek(2).clone())
|
||||||
@ -356,13 +366,16 @@ impl Interpreter {
|
|||||||
InstructionCost::GasMem(gas, mem)
|
InstructionCost::GasMem(gas, mem)
|
||||||
},
|
},
|
||||||
instructions::DELEGATECALL => {
|
instructions::DELEGATECALL => {
|
||||||
let gas = add_u256_usize(stack.peek(0), schedule.call_gas);
|
match add_u256_usize(stack.peek(0), schedule.call_gas) {
|
||||||
|
(_gas, true) => InstructionCost::GasMem(U256::zero(), RequiredMem::OutOfMemory),
|
||||||
|
(gas, false) => {
|
||||||
let mem = self.mem_max(
|
let mem = self.mem_max(
|
||||||
self.mem_needed(stack.peek(4), stack.peek(5)),
|
self.mem_needed(stack.peek(4), stack.peek(5)),
|
||||||
self.mem_needed(stack.peek(2), stack.peek(3))
|
self.mem_needed(stack.peek(2), stack.peek(3))
|
||||||
);
|
);
|
||||||
InstructionCost::GasMem(gas, mem)
|
InstructionCost::GasMem(gas, mem)
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
instructions::CREATE => {
|
instructions::CREATE => {
|
||||||
let gas = U256::from(schedule.create_gas);
|
let gas = U256::from(schedule.create_gas);
|
||||||
@ -393,9 +406,14 @@ impl Interpreter {
|
|||||||
InstructionCost::GasMemCopy(gas, mem_size, copy) => match mem_size {
|
InstructionCost::GasMemCopy(gas, mem_size, copy) => match mem_size {
|
||||||
RequiredMem::Mem(mem_size) => {
|
RequiredMem::Mem(mem_size) => {
|
||||||
let (mem_gas, new_mem_size) = self.mem_gas_cost(schedule, mem.size(), &mem_size);
|
let (mem_gas, new_mem_size) = self.mem_gas_cost(schedule, mem.size(), &mem_size);
|
||||||
let copy_gas = U256::from(schedule.copy_gas) * (add_u256_usize(©, 31) / U256::from(32));
|
match add_u256_usize(©, 31) {
|
||||||
|
(_c, true) => Err(evm::Error::OutOfGas),
|
||||||
|
(copy, false) => {
|
||||||
|
let copy_gas = U256::from(schedule.copy_gas) * (copy / U256::from(32));
|
||||||
let gas = try!(self.gas_add(try!(self.gas_add(gas, copy_gas)), mem_gas));
|
let gas = try!(self.gas_add(try!(self.gas_add(gas, copy_gas)), mem_gas));
|
||||||
Ok((gas, new_mem_size))
|
Ok((gas, new_mem_size))
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
RequiredMem::OutOfMemory => Err(evm::Error::OutOfGas)
|
RequiredMem::OutOfMemory => Err(evm::Error::OutOfGas)
|
||||||
}
|
}
|
||||||
@ -415,16 +433,16 @@ impl Interpreter {
|
|||||||
s * U256::from(schedule.memory_gas) + s * s / U256::from(schedule.quad_coeff_div)
|
s * U256::from(schedule.memory_gas) + s * s / U256::from(schedule.quad_coeff_div)
|
||||||
};
|
};
|
||||||
|
|
||||||
let req_mem_size = mem_size.low_u64() as usize;
|
let current_mem_size = U256::from(current_mem_size);
|
||||||
let req_mem_size_rounded = (req_mem_size + 31) / 32 * 32;
|
let req_mem_size_rounded = ((mem_size.clone() + U256::from(31)) >> 5) << 5;
|
||||||
let new_mem_gas = gas_for_mem(U256::from(req_mem_size_rounded));
|
let new_mem_gas = gas_for_mem(U256::from(req_mem_size_rounded));
|
||||||
let current_mem_gas = gas_for_mem(U256::from(current_mem_size));
|
let current_mem_gas = gas_for_mem(current_mem_size);
|
||||||
|
|
||||||
(if req_mem_size_rounded > current_mem_size {
|
(if req_mem_size_rounded > current_mem_size {
|
||||||
new_mem_gas - current_mem_gas
|
new_mem_gas - current_mem_gas
|
||||||
} else {
|
} else {
|
||||||
U256::zero()
|
U256::zero()
|
||||||
}, req_mem_size_rounded)
|
}, req_mem_size_rounded.low_u64() as usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -452,7 +470,9 @@ impl Interpreter {
|
|||||||
} else {
|
} else {
|
||||||
match offset.clone().overflowing_add(size.clone()) {
|
match offset.clone().overflowing_add(size.clone()) {
|
||||||
(_result, true) => RequiredMem::OutOfMemory,
|
(_result, true) => RequiredMem::OutOfMemory,
|
||||||
(result, false) => RequiredMem::Mem(result)
|
(result, false) => {
|
||||||
|
RequiredMem::Mem(result)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1009,8 +1029,8 @@ pub fn set_sign(value: U256, sign: bool) -> U256 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_u256_usize(value: &U256, num: usize) -> U256 {
|
fn add_u256_usize(value: &U256, num: usize) -> (U256, bool) {
|
||||||
value.clone() + U256::from(num)
|
value.clone().overflowing_add(U256::from(num))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn u256_to_address(value: &U256) -> Address {
|
fn u256_to_address(value: &U256) -> Address {
|
||||||
|
@ -168,9 +168,6 @@ fn do_json_test_for(vm: &VMType, json_data: &[u8]) -> Vec<String> {
|
|||||||
let json = Json::from_str(::std::str::from_utf8(json_data).unwrap()).expect("Json is invalid");
|
let json = Json::from_str(::std::str::from_utf8(json_data).unwrap()).expect("Json is invalid");
|
||||||
let mut failed = Vec::new();
|
let mut failed = Vec::new();
|
||||||
for (name, test) in json.as_object().unwrap() {
|
for (name, test) in json.as_object().unwrap() {
|
||||||
// if name != "CallToNameRegistrator0" {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
println!("name: {:?}", name);
|
println!("name: {:?}", name);
|
||||||
// sync io is usefull when something crashes in jit
|
// sync io is usefull when something crashes in jit
|
||||||
// ::std::io::stdout().write(&name.as_bytes());
|
// ::std::io::stdout().write(&name.as_bytes());
|
||||||
|
Loading…
Reference in New Issue
Block a user