Parse payload from panic
Impl payload empty str is none Update tests Clean Update wasm-tests
This commit is contained in:
parent
4a6b103f0e
commit
3d0616c1ae
@ -1 +1 @@
|
|||||||
Subproject commit 9a1fcbf0d4e73bea437577e807bc38c7ba243d80
|
Subproject commit d4920761f959a785c3ec15cf2848fc75795eb2d4
|
@ -31,6 +31,7 @@ mod result;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
mod env;
|
mod env;
|
||||||
|
mod panic_payload;
|
||||||
|
|
||||||
const DEFAULT_STACK_SPACE: u32 = 5 * 1024 * 1024;
|
const DEFAULT_STACK_SPACE: u32 = 5 * 1024 * 1024;
|
||||||
|
|
||||||
|
169
ethcore/wasm/src/panic_payload.rs
Normal file
169
ethcore/wasm/src/panic_payload.rs
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity.
|
||||||
|
|
||||||
|
// Parity is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// Parity is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use byteorder::{LittleEndian, ReadBytesExt};
|
||||||
|
use std::io;
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub struct PanicPayload {
|
||||||
|
pub msg: Option<String>,
|
||||||
|
pub file: Option<String>,
|
||||||
|
pub line: Option<u32>,
|
||||||
|
pub col: Option<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_string(rdr: &mut io::Cursor<&[u8]>) -> io::Result<Option<String>> {
|
||||||
|
let string_len = rdr.read_u32::<LittleEndian>()?;
|
||||||
|
let string = if string_len == 0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let mut content = vec![0; string_len as usize];
|
||||||
|
rdr.read_exact(&mut content)?;
|
||||||
|
Some(String::from_utf8_lossy(&content).into_owned())
|
||||||
|
};
|
||||||
|
Ok(string)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode(raw: &[u8]) -> PanicPayload {
|
||||||
|
let mut rdr = io::Cursor::new(raw);
|
||||||
|
let msg = read_string(&mut rdr).ok().and_then(|x| x);
|
||||||
|
let file = read_string(&mut rdr).ok().and_then(|x| x);
|
||||||
|
let line = rdr.read_u32::<LittleEndian>().ok();
|
||||||
|
let col = rdr.read_u32::<LittleEndian>().ok();
|
||||||
|
PanicPayload {
|
||||||
|
msg: msg,
|
||||||
|
file: file,
|
||||||
|
line: line,
|
||||||
|
col: col,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use byteorder::WriteBytesExt;
|
||||||
|
|
||||||
|
fn write_u32(payload: &mut Vec<u8>, val: u32) {
|
||||||
|
payload.write_u32::<LittleEndian>(val).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_bytes(payload: &mut Vec<u8>, bytes: &[u8]) {
|
||||||
|
write_u32(payload, bytes.len() as u32);
|
||||||
|
payload.extend(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn it_works() {
|
||||||
|
let mut raw = Vec::new();
|
||||||
|
write_bytes(&mut raw, b"msg");
|
||||||
|
write_bytes(&mut raw, b"file");
|
||||||
|
write_u32(&mut raw, 1);
|
||||||
|
write_u32(&mut raw, 2);
|
||||||
|
|
||||||
|
let payload = decode(&raw);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
payload,
|
||||||
|
PanicPayload {
|
||||||
|
msg: Some("msg".to_string()),
|
||||||
|
file: Some("file".to_string()),
|
||||||
|
line: Some(1),
|
||||||
|
col: Some(2),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn only_msg() {
|
||||||
|
let mut raw = Vec::new();
|
||||||
|
write_bytes(&mut raw, b"msg");
|
||||||
|
|
||||||
|
let payload = decode(&raw);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
payload,
|
||||||
|
PanicPayload {
|
||||||
|
msg: Some("msg".to_string()),
|
||||||
|
file: None,
|
||||||
|
line: None,
|
||||||
|
col: None,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn invalid_utf8() {
|
||||||
|
let mut raw = Vec::new();
|
||||||
|
write_bytes(&mut raw, b"\xF0\x90\x80msg");
|
||||||
|
write_bytes(&mut raw, b"file");
|
||||||
|
write_u32(&mut raw, 1);
|
||||||
|
write_u32(&mut raw, 2);
|
||||||
|
|
||||||
|
let payload = decode(&raw);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
payload,
|
||||||
|
PanicPayload {
|
||||||
|
msg: Some("<EFBFBD>msg".to_string()),
|
||||||
|
file: Some("file".to_string()),
|
||||||
|
line: Some(1),
|
||||||
|
col: Some(2),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn trailing_data() {
|
||||||
|
let mut raw = Vec::new();
|
||||||
|
write_bytes(&mut raw, b"msg");
|
||||||
|
write_bytes(&mut raw, b"file");
|
||||||
|
write_u32(&mut raw, 1);
|
||||||
|
write_u32(&mut raw, 2);
|
||||||
|
write_u32(&mut raw, 0xdeadbeef);
|
||||||
|
|
||||||
|
let payload = decode(&raw);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
payload,
|
||||||
|
PanicPayload {
|
||||||
|
msg: Some("msg".to_string()),
|
||||||
|
file: Some("file".to_string()),
|
||||||
|
line: Some(1),
|
||||||
|
col: Some(2),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn empty_str_is_none() {
|
||||||
|
let mut raw = Vec::new();
|
||||||
|
write_bytes(&mut raw, b"msg");
|
||||||
|
write_bytes(&mut raw, b"");
|
||||||
|
|
||||||
|
let payload = decode(&raw);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
payload,
|
||||||
|
PanicPayload {
|
||||||
|
msg: Some("msg".to_string()),
|
||||||
|
file: None,
|
||||||
|
line: None,
|
||||||
|
col: None,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -21,6 +21,7 @@ use std::sync::Arc;
|
|||||||
use byteorder::{LittleEndian, ByteOrder};
|
use byteorder::{LittleEndian, ByteOrder};
|
||||||
|
|
||||||
use vm;
|
use vm;
|
||||||
|
use panic_payload;
|
||||||
use parity_wasm::interpreter;
|
use parity_wasm::interpreter;
|
||||||
use wasm_utils::rules;
|
use wasm_utils::rules;
|
||||||
use bigint::prelude::U256;
|
use bigint::prelude::U256;
|
||||||
@ -626,12 +627,26 @@ impl<'a, 'b> Runtime<'a, 'b> {
|
|||||||
fn user_panic(&mut self, context: InterpreterCallerContext)
|
fn user_panic(&mut self, context: InterpreterCallerContext)
|
||||||
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
-> Result<Option<interpreter::RuntimeValue>, InterpreterError>
|
||||||
{
|
{
|
||||||
let msg_len = context.value_stack.pop_as::<i32>()? as u32;
|
let payload_len = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
let msg_ptr = context.value_stack.pop_as::<i32>()? as u32;
|
let payload_ptr = context.value_stack.pop_as::<i32>()? as u32;
|
||||||
|
|
||||||
let msg = String::from_utf8(self.memory.get(msg_ptr, msg_len as usize)?)
|
|
||||||
.map_err(|_| UserTrap::BadUtf8)?;
|
|
||||||
|
|
||||||
|
let raw_payload = self.memory.get(payload_ptr, payload_len as usize)?;
|
||||||
|
let payload = panic_payload::decode(&raw_payload);
|
||||||
|
let msg = format!(
|
||||||
|
"{msg}, {file}:{line}:{col}",
|
||||||
|
msg = payload
|
||||||
|
.msg
|
||||||
|
.as_ref()
|
||||||
|
.map(String::as_ref)
|
||||||
|
.unwrap_or("<msg was stripped>"),
|
||||||
|
file = payload
|
||||||
|
.file
|
||||||
|
.as_ref()
|
||||||
|
.map(String::as_ref)
|
||||||
|
.unwrap_or("<unknown>"),
|
||||||
|
line = payload.line.unwrap_or(0),
|
||||||
|
col = payload.col.unwrap_or(0)
|
||||||
|
);
|
||||||
trace!(target: "wasm", "Contract custom panic message: {}", msg);
|
trace!(target: "wasm", "Contract custom panic message: {}", msg);
|
||||||
|
|
||||||
Err(UserTrap::Panic(msg).into())
|
Err(UserTrap::Panic(msg).into())
|
||||||
|
@ -180,7 +180,7 @@ fn dispersion() {
|
|||||||
result,
|
result,
|
||||||
vec![0u8, 0, 125, 11, 197, 7, 255, 8, 19, 0]
|
vec![0u8, 0, 125, 11, 197, 7, 255, 8, 19, 0]
|
||||||
);
|
);
|
||||||
assert_eq!(gas_left, U256::from(99_469));
|
assert_eq!(gas_left, U256::from(96_961));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -208,7 +208,7 @@ fn suicide_not() {
|
|||||||
result,
|
result,
|
||||||
vec![0u8]
|
vec![0u8]
|
||||||
);
|
);
|
||||||
assert_eq!(gas_left, U256::from(99_724));
|
assert_eq!(gas_left, U256::from(97_290));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -240,7 +240,7 @@ fn suicide() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
assert!(ext.suicides.contains(&refund));
|
assert!(ext.suicides.contains(&refund));
|
||||||
assert_eq!(gas_left, U256::from(99_663));
|
assert_eq!(gas_left, U256::from(97_249));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -312,7 +312,7 @@ fn call_code() {
|
|||||||
assert!(ext.calls.contains(
|
assert!(ext.calls.contains(
|
||||||
&FakeCall {
|
&FakeCall {
|
||||||
call_type: FakeCallType::Call,
|
call_type: FakeCallType::Call,
|
||||||
gas: U256::from(98_709),
|
gas: U256::from(98_713),
|
||||||
sender_address: Some(sender),
|
sender_address: Some(sender),
|
||||||
receive_address: Some(receiver),
|
receive_address: Some(receiver),
|
||||||
value: None,
|
value: None,
|
||||||
@ -324,7 +324,7 @@ fn call_code() {
|
|||||||
// siphash result
|
// siphash result
|
||||||
let res = LittleEndian::read_u32(&result[..]);
|
let res = LittleEndian::read_u32(&result[..]);
|
||||||
assert_eq!(res, 4198595614);
|
assert_eq!(res, 4198595614);
|
||||||
assert_eq!(gas_left, U256::from(93_851));
|
assert_eq!(gas_left, U256::from(93_855));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -357,7 +357,7 @@ fn call_static() {
|
|||||||
assert!(ext.calls.contains(
|
assert!(ext.calls.contains(
|
||||||
&FakeCall {
|
&FakeCall {
|
||||||
call_type: FakeCallType::Call,
|
call_type: FakeCallType::Call,
|
||||||
gas: U256::from(98_709),
|
gas: U256::from(98_713),
|
||||||
sender_address: Some(sender),
|
sender_address: Some(sender),
|
||||||
receive_address: Some(receiver),
|
receive_address: Some(receiver),
|
||||||
value: None,
|
value: None,
|
||||||
@ -370,7 +370,7 @@ fn call_static() {
|
|||||||
let res = LittleEndian::read_u32(&result[..]);
|
let res = LittleEndian::read_u32(&result[..]);
|
||||||
assert_eq!(res, 317632590);
|
assert_eq!(res, 317632590);
|
||||||
|
|
||||||
assert_eq!(gas_left, U256::from(93_851));
|
assert_eq!(gas_left, U256::from(93_855));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Realloc test
|
// Realloc test
|
||||||
@ -393,7 +393,7 @@ fn realloc() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
assert_eq!(result, vec![0u8; 2]);
|
assert_eq!(result, vec![0u8; 2]);
|
||||||
assert_eq!(gas_left, U256::from(99_787));
|
assert_eq!(gas_left, U256::from(97_278));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that contract's ability to read from a storage
|
// Tests that contract's ability to read from a storage
|
||||||
@ -419,7 +419,7 @@ fn storage_read() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(Address::from(&result[12..32]), address);
|
assert_eq!(Address::from(&result[12..32]), address);
|
||||||
assert_eq!(gas_left, U256::from(99_702));
|
assert_eq!(gas_left, U256::from(99_706));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests keccak calculation
|
// Tests keccak calculation
|
||||||
@ -445,7 +445,7 @@ fn keccak() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"));
|
assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"));
|
||||||
assert_eq!(gas_left, U256::from(84_520));
|
assert_eq!(gas_left, U256::from(82_009));
|
||||||
}
|
}
|
||||||
|
|
||||||
// memcpy test.
|
// memcpy test.
|
||||||
@ -477,7 +477,7 @@ fn memcpy() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(result, test_payload);
|
assert_eq!(result, test_payload);
|
||||||
assert_eq!(gas_left, U256::from(75_324));
|
assert_eq!(gas_left, U256::from(72_773));
|
||||||
}
|
}
|
||||||
|
|
||||||
// memmove test.
|
// memmove test.
|
||||||
@ -509,7 +509,7 @@ fn memmove() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(result, test_payload);
|
assert_eq!(result, test_payload);
|
||||||
assert_eq!(gas_left, U256::from(75_324));
|
assert_eq!(gas_left, U256::from(72_773));
|
||||||
}
|
}
|
||||||
|
|
||||||
// memset test
|
// memset test
|
||||||
@ -534,7 +534,7 @@ fn memset() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(result, vec![228u8; 8192]);
|
assert_eq!(result, vec![228u8; 8192]);
|
||||||
assert_eq!(gas_left, U256::from(75_324));
|
assert_eq!(gas_left, U256::from(72_763));
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! reqrep_test {
|
macro_rules! reqrep_test {
|
||||||
@ -591,7 +591,7 @@ fn math_add() {
|
|||||||
U256::from_dec_str("1888888888888888888888888888887").unwrap(),
|
U256::from_dec_str("1888888888888888888888888888887").unwrap(),
|
||||||
(&result[..]).into()
|
(&result[..]).into()
|
||||||
);
|
);
|
||||||
assert_eq!(gas_left, U256::from(98_576));
|
assert_eq!(gas_left, U256::from(96_084));
|
||||||
}
|
}
|
||||||
|
|
||||||
// multiplication
|
// multiplication
|
||||||
@ -613,7 +613,7 @@ fn math_mul() {
|
|||||||
U256::from_dec_str("888888888888888888888888888887111111111111111111111111111112").unwrap(),
|
U256::from_dec_str("888888888888888888888888888887111111111111111111111111111112").unwrap(),
|
||||||
(&result[..]).into()
|
(&result[..]).into()
|
||||||
);
|
);
|
||||||
assert_eq!(gas_left, U256::from(97_726));
|
assert_eq!(gas_left, U256::from(95_234));
|
||||||
}
|
}
|
||||||
|
|
||||||
// subtraction
|
// subtraction
|
||||||
@ -635,7 +635,7 @@ fn math_sub() {
|
|||||||
U256::from_dec_str("111111111111111111111111111111").unwrap(),
|
U256::from_dec_str("111111111111111111111111111111").unwrap(),
|
||||||
(&result[..]).into()
|
(&result[..]).into()
|
||||||
);
|
);
|
||||||
assert_eq!(gas_left, U256::from(98_568));
|
assert_eq!(gas_left, U256::from(96_076));
|
||||||
}
|
}
|
||||||
|
|
||||||
// subtraction with overflow
|
// subtraction with overflow
|
||||||
@ -677,7 +677,7 @@ fn math_div() {
|
|||||||
U256::from_dec_str("1125000").unwrap(),
|
U256::from_dec_str("1125000").unwrap(),
|
||||||
(&result[..]).into()
|
(&result[..]).into()
|
||||||
);
|
);
|
||||||
assert_eq!(gas_left, U256::from(91_564));
|
assert_eq!(gas_left, U256::from(89_074));
|
||||||
}
|
}
|
||||||
|
|
||||||
// This test checks the ability of wasm contract to invoke
|
// This test checks the ability of wasm contract to invoke
|
||||||
@ -765,7 +765,7 @@ fn externs() {
|
|||||||
"Gas limit requested and returned does not match"
|
"Gas limit requested and returned does not match"
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(gas_left, U256::from(97_740));
|
assert_eq!(gas_left, U256::from(95_291));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -791,7 +791,7 @@ fn embedded_keccak() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"));
|
assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87"));
|
||||||
assert_eq!(gas_left, U256::from(84_520));
|
assert_eq!(gas_left, U256::from(82_009));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This test checks the correctness of log extern
|
/// This test checks the correctness of log extern
|
||||||
@ -826,5 +826,5 @@ fn events() {
|
|||||||
assert_eq!(&log_entry.data, b"gnihtemos");
|
assert_eq!(&log_entry.data, b"gnihtemos");
|
||||||
|
|
||||||
assert_eq!(&result, b"gnihtemos");
|
assert_eq!(&result, b"gnihtemos");
|
||||||
assert_eq!(gas_left, U256::from(82_721));
|
assert_eq!(gas_left, U256::from(80_199));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user