Commit 6505b485 authored by Richard Musiol's avatar Richard Musiol Committed by Brad Fitzpatrick

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 <neelance@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarCherry Zhang <cherryyz@google.com>
parent 65b89c35
......@@ -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
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment