From 6505b4853196a172cfe4dd161072dfb8afb6b0be Mon Sep 17 00:00:00 2001 From: Richard Musiol Date: Tue, 30 Apr 2019 19:16:23 +0200 Subject: [PATCH] syscall: on wasm, do not use typed array asynchronously The underlying buffer of a typed array becomes invalid as soon as we grow the WebAssembly memory, which can happen at any time while Go code runs. This is a known limitation, see https://golang.org/cl/155778. As a consequence, using a typed array with one of the asynchronous read/write operations of Node.js' fs module is dangerous, since it may become invalid while the asynchronous operation has not finished yet. The result of this situation is most likely undefined. I am not aware of any nice solution to this issue, so this change adds a workaround of using an additional typed array which is not backed by WebAssembly memory and copying the bytes between the two typed arrays. Maybe WebAssembly will come up with a better solution in the future. Fixes #31702. Change-Id: Iafc2a0fa03c81db414520bd45a1a17c00080b61e Reviewed-on: https://go-review.googlesource.com/c/go/+/174304 Run-TryBot: Richard Musiol TryBot-Result: Gobot Gobot Reviewed-by: Cherry Zhang --- src/syscall/fs_js.go | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/src/syscall/fs_js.go b/src/syscall/fs_js.go index 89459979af..3c2dac3579 100644 --- a/src/syscall/fs_js.go +++ b/src/syscall/fs_js.go @@ -19,6 +19,7 @@ func now() (sec int64, nsec int32) var jsProcess = js.Global().Get("process") var jsFS = js.Global().Get("fs") var constants = jsFS.Get("constants") +var uint8Array = js.Global().Get("Uint8Array") var ( nodeWRONLY = constants.Get("O_WRONLY").Int() @@ -378,12 +379,16 @@ func Read(fd int, b []byte) (int, error) { return n, err } - a := js.TypedArrayOf(b) - n, err := fsCall("read", fd, a, 0, len(b), nil) - a.Release() + buf := uint8Array.New(len(b)) + n, err := fsCall("read", fd, buf, 0, len(b), nil) if err != nil { return 0, err } + + a := js.TypedArrayOf(b) + a.Call("set", buf) + a.Release() + n2 := n.Int() f.pos += int64(n2) return n2, err @@ -402,8 +407,11 @@ func Write(fd int, b []byte) (int, error) { } a := js.TypedArrayOf(b) - n, err := fsCall("write", fd, a, 0, len(b), nil) + buf := uint8Array.New(len(b)) + buf.Call("set", a) a.Release() + + n, err := fsCall("write", fd, buf, 0, len(b), nil) if err != nil { return 0, err } @@ -413,19 +421,26 @@ func Write(fd int, b []byte) (int, error) { } func Pread(fd int, b []byte, offset int64) (int, error) { - a := js.TypedArrayOf(b) - n, err := fsCall("read", fd, a, 0, len(b), offset) - a.Release() + buf := uint8Array.New(len(b)) + n, err := fsCall("read", fd, buf, 0, len(b), offset) if err != nil { return 0, err } + + a := js.TypedArrayOf(b) + a.Call("set", buf) + a.Release() + return n.Int(), nil } func Pwrite(fd int, b []byte, offset int64) (int, error) { a := js.TypedArrayOf(b) - n, err := fsCall("write", fd, a, 0, len(b), offset) + buf := uint8Array.New(len(b)) + buf.Call("set", a) a.Release() + + n, err := fsCall("write", fd, buf, 0, len(b), offset) if err != nil { return 0, err } -- 2.48.1