Repository: go
Issue: wasm: Writing non-ASCII text to stdout or stderr fails on Windows
Labels: OS-Windows,NeedsInvestigation,arch-wasm

<!--
Please answer these questions before submitting your issue. Thanks!
For questions please use one of our forums: https://github.com/golang/go/wiki/Questions
-->

### What version of Go are you using (`go version`)?

<pre>
$ go version
go version go1.15.7 windows/amd64
</pre>

### Does this issue reproduce with the latest release?

Yes

### What operating system and processor architecture are you using (`go env`)?

<details><summary><code>go env</code> Output</summary><br><pre>
$ go env
set GO111MODULE=
set GOARCH=wasm
set GOBIN=
set GOCACHE=C:\Users\User\AppData\Local\go-build
set GOENV=C:\Users\User\AppData\Roaming\go\env
set GOEXE=
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOINSECURE=
set GOMODCACHE=C:\Users\User\go\pkg\mod
set GONOPROXY=
set GONOSUMDB=
set GOOS=js
set GOPATH=C:\Users\User\go
set GOPRIVATE=
set GOPROXY=https://proxy.golang.org,direct
set GOROOT=c:\go
set GOSUMDB=sum.golang.org
set GOTMPDIR=
set GOTOOLDIR=c:\go\pkg\tool\windows_amd64
set GCCGO=gccgo
set GOWASM=
set AR=ar
set CC=gcc
set CXX=g++
set CGO_ENABLED=0
set GOMOD=
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-fPIC -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=C:\Users\User\AppData\Local\Temp\go-build540642258=/tmp/go-build -gno-record-gcc-switches
</pre></details>

### What did you do?

<!--
If possible, provide a recipe for reproducing the error.
A complete runnable program is good.
A link on play.golang.org is best.
-->

Code:

```go
package main

import "fmt"

func main() {
  fmt.Printf("π\n")
}
```

Build with:

```
C:\Users\User\Desktop>set GOROOT=js
C:\Users\User\Desktop>set GOARCH=wasm
C:\Users\User\Desktop>go build -o main.wasm main.go
```

### What did you expect to see?

```
C:\Users\User\Desktop>node c:\go\misc\wasm\wasm_exec.js main.wasm
π
```

### What did you see instead?

```
C:\Users\User\Desktop>node c:\go\misc\wasm\wasm_exec.js main.wasm
╧Ç
```

This appears to be because of a bug in node: https://github.com/nodejs/node/issues/24550. Unfortunately the bug was closed as "won't fix" (not sure why). But it seems to be easy to work around from Go's end by changing the JavaScript wrapper script to manually forward file descriptors 1 and 2 to `process.stdout` and `process.stderr` respectively:

```diff
--- c:\go\misc\wasm\wasm_exec.js
+++ c:\go\misc\wasm\wasm_exec.js
@@ -29,7 +29,31 @@
 	if (!global.fs && global.require) {
 		const fs = require("fs");
 		if (Object.keys(fs) !== 0) {
-			global.fs = fs;
+			global.fs = Object.assign({}, fs, {
+				// Work around a bug in node: https://github.com/nodejs/node/issues/24550
+				write(fd, buf, offset, length, position, callback) {
+					if (offset === 0 && length === buf.length && position === null) {
+						if (fd === process.stdout.fd) {
+							try {
+								process.stdout.write(buf, err => {
+									if (err) callback(err, 0, null);
+									else callback(null, length, buf);
+								});
+							} catch (err) {
+								callback(err, 0, null);
+							}
+							return;
+						}
+						if (fd === process.stderr.fd) {
+							try {
+								process.stderr.write(buf, err => {
+									if (err) callback(err, 0, null);
+									else callback(null, length, buf);
+								});
+							} catch (err) {
+								callback(err, 0, null);
+							}
+							return;
+						}
+					}
+					fs.write(fd, buf, offset, length, position, callback);
+				},
+			});
 		}
 	}
 ```