]> Cypherpunks repositories - gostls13.git/commitdiff
syscall: on wasm, do not use typed array asynchronously
authorRichard Musiol <mail@richard-musiol.de>
Tue, 30 Apr 2019 17:16:23 +0000 (19:16 +0200)
committerBrad Fitzpatrick <bradfitz@golang.org>
Tue, 30 Apr 2019 22:41:20 +0000 (22:41 +0000)
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: Cherry Zhang <cherryyz@google.com>
src/syscall/fs_js.go

index 89459979af154fd9affc94003f7fab612bac9f12..3c2dac3579a7c42958944921d5fdad6f779bb163 100644 (file)
@@ -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
        }