diff --git a/CHANGELOG_UNRELEASED.md b/CHANGELOG_UNRELEASED.md index 1d1a4fec55..cbfa3270b6 100644 --- a/CHANGELOG_UNRELEASED.md +++ b/CHANGELOG_UNRELEASED.md @@ -29,6 +29,7 @@ ### Owasm +- (impv) [\#1936](https://github.com/bandprotocol/bandchain/pull/1936) Return error if writing beyond the span capacity. - (impv) [#\1941](https://github.com/bandprotocol/bandchain/pull/1941) Fix how to build share object in Linux. - (feat) [\#1922](https://github.com/bandprotocol/bandchain/pull/1922) Add wat to wasm function. diff --git a/go-owasm/api/bindings.h b/go-owasm/api/bindings.h index 24186897bc..bcd8e47335 100644 --- a/go-owasm/api/bindings.h +++ b/go-owasm/api/bindings.h @@ -12,6 +12,7 @@ enum Error { ResolveNamesError = 5, ValidateError = 6, UnknownError = 7, + SpanExceededCapacityError = 8, }; typedef int32_t Error; diff --git a/go-owasm/api/error.go b/go-owasm/api/error.go index c81ecb3b98..cb339ee554 100644 --- a/go-owasm/api/error.go +++ b/go-owasm/api/error.go @@ -5,13 +5,14 @@ import ( ) var ( - ErrCompliationError = errors.New("compile fail") - ErrRunError = errors.New("run fail") - ErrParseError = errors.New("parse fail") - ErrWriteBinaryError = errors.New("write binary fail") - ErrResolvesNamesFail = errors.New("resolve names fail") - ErrValidateError = errors.New("validate fail") - ErrUnknownError = errors.New("unknown error") + ErrCompliationFail = errors.New("compile fail") + ErrRunFail = errors.New("run fail") + ErrParseFail = errors.New("parse fail") + ErrWriteBinaryFail = errors.New("write binary fail") + ErrResolvesNamesFail = errors.New("resolve names fail") + ErrValidateFail = errors.New("validate fail") + ErrUnknownError = errors.New("unknown error") + ErrSpanExceededCapacity = errors.New("span exceeded capacity") ) // parseError - returns parsed error from errors code on bindings.h @@ -20,19 +21,21 @@ func parseError(code int32) error { case 0: return nil case 1: - return ErrCompliationError + return ErrCompliationFail case 2: - return ErrRunError + return ErrRunFail case 3: - return ErrParseError + return ErrParseFail case 4: - return ErrWriteBinaryError + return ErrWriteBinaryFail case 5: return ErrResolvesNamesFail case 6: - return ErrValidateError + return ErrValidateFail case 7: return ErrUnknownError + case 8: + return ErrSpanExceededCapacity default: return ErrUnknownError } diff --git a/go-owasm/api/lib.go b/go-owasm/api/lib.go index 212ca68808..f8bd4e0e85 100644 --- a/go-owasm/api/lib.go +++ b/go-owasm/api/lib.go @@ -24,10 +24,10 @@ import ( "unsafe" ) -func Compile(code []byte) ([]byte, error) { +func Compile(code []byte, spanSize int) ([]byte, error) { inputSpan := copySpan(code) defer freeSpan(inputSpan) - outputSpan := newSpan(SpanSize) + outputSpan := newSpan(spanSize) defer freeSpan(outputSpan) err := parseError(int32(C.do_compile(inputSpan, &outputSpan))) return readSpan(outputSpan), err @@ -61,10 +61,10 @@ func run(code []byte, isPrepare bool, env EnvInterface) error { }))) } -func Wat2Wasm(code []byte) ([]byte, error) { +func Wat2Wasm(code []byte, spanSize int) ([]byte, error) { inputSpan := copySpan(code) defer freeSpan(inputSpan) - outputSpan := newSpan(SpanSize) + outputSpan := newSpan(spanSize) defer freeSpan(outputSpan) err := parseError(int32(C.do_wat2wasm(inputSpan, &outputSpan))) return readSpan(outputSpan), err diff --git a/go-owasm/api/lib_test.go b/go-owasm/api/lib_test.go index 2c8c0c5342..de3f78cace 100644 --- a/go-owasm/api/lib_test.go +++ b/go-owasm/api/lib_test.go @@ -8,6 +8,10 @@ import ( "github.com/stretchr/testify/require" ) +const ( + SpanSize = 1 * 1024 * 1024 +) + func readWatFile(fileName string) []byte { code, err := ioutil.ReadFile(fmt.Sprintf("./../wasm/%s.wat", fileName)) if err != nil { @@ -26,7 +30,7 @@ func readWasmFile(fileName string) []byte { func TestSuccessWatToOwasm(t *testing.T) { code := readWatFile("test") - wasm, err := Wat2Wasm(code) + wasm, err := Wat2Wasm(code, SpanSize) require.NoError(t, err) expectedWasm := readWasmFile("test") @@ -35,12 +39,19 @@ func TestSuccessWatToOwasm(t *testing.T) { func TestFailEmptyWatContent(t *testing.T) { code := []byte("") - _, err := Wat2Wasm(code) - require.Equal(t, ErrParseError, err) + _, err := Wat2Wasm(code, SpanSize) + require.Equal(t, ErrParseFail, err) } func TestFailInvalidWatContent(t *testing.T) { code := []byte("invalid wat content") - _, err := Wat2Wasm(code) - require.Equal(t, ErrParseError, err) + _, err := Wat2Wasm(code, SpanSize) + require.Equal(t, ErrParseFail, err) +} + +func TestFailSpanExceededCapacity(t *testing.T) { + code := readWatFile("test") + smallSpanSize := 10 + _, err := Wat2Wasm(code, smallSpanSize) + require.EqualError(t, err, "span exceeded capacity") } diff --git a/go-owasm/api/libgo_owasm.dylib b/go-owasm/api/libgo_owasm.dylib index 433e23ef3a..ddbbd5cf13 100755 Binary files a/go-owasm/api/libgo_owasm.dylib and b/go-owasm/api/libgo_owasm.dylib differ diff --git a/go-owasm/api/libgo_owasm.so b/go-owasm/api/libgo_owasm.so index a02d34a007..fd31be522c 100755 Binary files a/go-owasm/api/libgo_owasm.so and b/go-owasm/api/libgo_owasm.so differ diff --git a/go-owasm/api/span.go b/go-owasm/api/span.go index d80d4f4297..bbcd0545ed 100644 --- a/go-owasm/api/span.go +++ b/go-owasm/api/span.go @@ -4,10 +4,6 @@ package api import "C" import "unsafe" -const ( - SpanSize = 1 * 1024 * 1024 -) - func newSpan(size int) C.Span { return C.Span{ ptr: (*C.uint8_t)(C.malloc(C.uintptr_t(size))), diff --git a/go-owasm/go.mod b/go-owasm/go.mod index 0f7e9b6065..d25c7fb287 100644 --- a/go-owasm/go.mod +++ b/go-owasm/go.mod @@ -1,3 +1,5 @@ module github.com/bandprotocol/bandchain/go-owasm go 1.13 + +require github.com/stretchr/testify v1.6.1 diff --git a/go-owasm/go.sum b/go-owasm/go.sum index e69de29bb2..56d62e7c22 100644 --- a/go-owasm/go.sum +++ b/go-owasm/go.sum @@ -0,0 +1,10 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/go-owasm/main.go b/go-owasm/main.go index fd43191137..6fd5477181 100644 --- a/go-owasm/main.go +++ b/go-owasm/main.go @@ -42,9 +42,9 @@ func (e *Env) GetExternalData(eid int64, vid int64) []byte { return []byte("switez") } -func Wat2Wasm(fileName string) error { +func Wat2Wasm(fileName string, spanSize int) error { code, _ := ioutil.ReadFile(fmt.Sprintf("./wasm/%s.wat", fileName)) - wasm, err := api.Wat2Wasm(code) + wasm, err := api.Wat2Wasm(code, spanSize) if err != nil { panic(err) } @@ -65,7 +65,8 @@ func Wat2Wasm(fileName string) error { func main() { fmt.Println("Hello, World!") code, _ := ioutil.ReadFile("./wasm/fun3.wat") - wasm, e := api.Wat2Wasm(code) + spanSize := 1 * 1024 * 1024 + wasm, e := api.Wat2Wasm(code, spanSize) fmt.Println("wasm", wasm) fmt.Println(e) } diff --git a/go-owasm/src/error.rs b/go-owasm/src/error.rs index b4e78aeaa7..8333a3bc12 100644 --- a/go-owasm/src/error.rs +++ b/go-owasm/src/error.rs @@ -1,4 +1,5 @@ #[repr(i32)] +#[derive(Debug, PartialEq)] pub enum Error { NoError = 0, CompliationError = 1, @@ -7,5 +8,6 @@ pub enum Error { WriteBinaryError = 4, ResolveNamesError = 5, ValidateError = 6, - UnknownError = 7 + UnknownError = 7, + SpanExceededCapacityError = 8 } diff --git a/go-owasm/src/lib.rs b/go-owasm/src/lib.rs index 8bf8122c35..1d1028ef2c 100644 --- a/go-owasm/src/lib.rs +++ b/go-owasm/src/lib.rs @@ -19,10 +19,7 @@ use wabt::wat2wasm; pub extern "C" fn do_compile(input: Span, output: &mut Span) -> Error { // TODO: Define error when compile code. match compile(input.read()) { - Ok(out) => { - output.write(&out); - Error::NoError - } + Ok(out) => output.write(&out), Err(_) => Error::CompliationError, } } @@ -38,10 +35,7 @@ pub extern "C" fn do_run(code: Span, is_prepare: bool, env: Env) -> Error { #[no_mangle] pub extern "C" fn do_wat2wasm(input: Span, output: &mut Span) -> Error { match wat2wasm(input.read()) { - Ok(_wasm) => { - output.write(&_wasm); - Error::NoError - }, + Ok(_wasm) => output.write(&_wasm), Err(e) => { match e.kind() { wabt::ErrorKind::Parse(_) => Error::ParseError, diff --git a/go-owasm/src/span.rs b/go-owasm/src/span.rs index e8399d7e2b..e60cbab070 100644 --- a/go-owasm/src/span.rs +++ b/go-owasm/src/span.rs @@ -1,3 +1,5 @@ +use crate::error::Error; + #[derive(Copy, Clone)] #[repr(C)] pub struct Span { @@ -7,7 +9,7 @@ pub struct Span { } impl Span { - // TODO + // Create span. pub fn create(data: &[u8]) -> Span { Span { ptr: data.as_ptr() as *mut u8, @@ -15,22 +17,67 @@ impl Span { cap: data.len(), } } - - /// TODO + + /// Read data from the span. pub fn read(&self) -> &[u8] { unsafe { std::slice::from_raw_parts(self.ptr, self.len) } } - /// TODO - pub fn write(&mut self, data: &[u8]) { - // TODO: Do not allow write if data.len() exceeds cap. + /// Write data to the span. + pub fn write(&mut self, data: &[u8]) -> Error { + if self.len + data.len() > self.cap { + return Error::SpanExceededCapacityError + } + unsafe { std::ptr::copy(data.as_ptr(), self.ptr.offset(self.len as isize), data.len()) } self.len += data.len(); - unsafe { std::ptr::copy(data.as_ptr(), self.ptr, data.len()) } + Error::NoError } } #[cfg(test)] mod test { - // use super::*; - // TODO + use super::*; + + #[test] + fn test_create_and_read_span_ok() { + let data: Vec = vec![1, 2, 3, 4, 5]; + let span = Span::create(data.as_slice()); + let span_data = &span.read(); + let span_data_vec = span_data.to_vec(); + assert_eq!(span_data_vec.len(), data.len()); + assert_eq!(span_data_vec[0], data[0]); + assert_eq!(span_data_vec[1], data[1]); + assert_eq!(span_data_vec[2], data[2]); + assert_eq!(span_data_vec[3], data[3]); + assert_eq!(span_data_vec[4], data[4]); + } + + #[test] + fn test_write_span_ok() { + let mut empty_space = vec![0u8; 32]; + let mut span = Span{ ptr: empty_space.as_mut_ptr(), len: 0, cap: 32 }; + + let data: Vec = vec![1, 2, 3, 4, 5]; + assert_eq!(span.write(data.as_slice()), Error::NoError); + assert_eq!(span.len, 5); + assert_eq!(span.cap, 32); + assert_eq!(empty_space[0], 1); + assert_eq!(empty_space[5], 0); + + assert_eq!(span.write(data.as_slice()), Error::NoError); + assert_eq!(span.len, 10); + assert_eq!(span.cap, 32); + assert_eq!(empty_space[0], 1); + assert_eq!(empty_space[5], 1); + assert_eq!(empty_space[9], 5); + } + + #[test] + fn test_write_span_fail() { + let mut empty_space = vec![0u8; 3]; + let mut span = Span{ ptr: empty_space.as_mut_ptr(), len: 0, cap: 3 }; + let data: Vec = vec![1, 2, 3, 4, 5]; + span.write(data.as_slice()); + assert_eq!(span.write(data.as_slice()), Error::SpanExceededCapacityError); + } }