Skip to content
This repository has been archived by the owner on Nov 16, 2022. It is now read-only.

go-owasm: Return error if writing beyond the provided span length #1936

Merged
merged 16 commits into from
Jun 15, 2020
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG_UNRELEASED.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,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.

Expand Down
1 change: 1 addition & 0 deletions go-owasm/api/bindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ enum Error {
ResolveNamesError = 5,
ValidateError = 6,
UnknownError = 7,
SpanExceededCapacityError = 8,
};
typedef int32_t Error;

Expand Down
27 changes: 15 additions & 12 deletions go-owasm/api/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}
Expand Down
8 changes: 4 additions & 4 deletions go-owasm/api/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
21 changes: 16 additions & 5 deletions go-owasm/api/lib_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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")
Expand All @@ -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")
}
Binary file modified go-owasm/api/libgo_owasm.dylib
Binary file not shown.
Binary file modified go-owasm/api/libgo_owasm.so
Binary file not shown.
4 changes: 0 additions & 4 deletions go-owasm/api/span.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))),
Expand Down
2 changes: 2 additions & 0 deletions go-owasm/go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
module github.com/bandprotocol/bandchain/go-owasm

go 1.13

require github.com/stretchr/testify v1.6.1
10 changes: 10 additions & 0 deletions go-owasm/go.sum
Original file line number Diff line number Diff line change
@@ -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=
7 changes: 4 additions & 3 deletions go-owasm/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand All @@ -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)
}
4 changes: 3 additions & 1 deletion go-owasm/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#[repr(i32)]
#[derive(Debug, PartialEq)]
pub enum Error {
NoError = 0,
CompliationError = 1,
Expand All @@ -7,5 +8,6 @@ pub enum Error {
WriteBinaryError = 4,
ResolveNamesError = 5,
ValidateError = 6,
UnknownError = 7
UnknownError = 7,
SpanExceededCapacityError = 8
}
10 changes: 2 additions & 8 deletions go-owasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
}
Expand All @@ -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,
Expand Down
65 changes: 56 additions & 9 deletions go-owasm/src/span.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::error::Error;

#[derive(Copy, Clone)]
#[repr(C)]
pub struct Span {
Expand All @@ -7,30 +9,75 @@ pub struct Span {
}

impl Span {
// TODO
// Create span.
pub fn create(data: &[u8]) -> Span {
Span {
ptr: data.as_ptr() as *mut u8,
len: data.len(),
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<u8> = 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<u8> = 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<u8> = vec![1, 2, 3, 4, 5];
span.write(data.as_slice());
assert_eq!(span.write(data.as_slice()), Error::SpanExceededCapacityError);
}
}