x/ref: cgo Errors escape non-utf8 runes

Java in particular is extremely upset by characters like 0xfe.
So much so that it will crash, so we are going to replace such
invalid characters with the Unicode unknown character.

In order to help find out the root cause of these invalid
characters, I have added:
- panic on normal strings if they have an invalid char. This
  should never actually happen, so it's worth panicking.
- vlog.Errorf for the error messages and stacks. We escape these
  for now, since we know of multiple errors that might lead to an
  invalid character in these strings.

Change-Id: Ic1e0f19c6f62324dd7bf56ec6aee5a9cd07eab74
diff --git a/services/syncbase/bridge/cgo/types.go b/services/syncbase/bridge/cgo/types.go
index 3ca05a1..0ac77ad 100644
--- a/services/syncbase/bridge/cgo/types.go
+++ b/services/syncbase/bridge/cgo/types.go
@@ -6,6 +6,9 @@
 
 import (
 	"bytes"
+	"fmt"
+	"strings"
+	"unicode/utf8"
 	"unsafe"
 
 	"v.io/v23/security/access"
@@ -13,6 +16,7 @@
 	"v.io/v23/syncbase"
 	"v.io/v23/verror"
 	"v.io/v23/vom"
+	"v.io/x/lib/vlog"
 	"v.io/x/ref/services/syncbase/discovery"
 )
 
@@ -274,6 +278,9 @@
 
 func (x *C.v23_syncbase_String) init(s string) {
 	x.n = C.int(len(s))
+	if !utf8.ValidString(s) {
+		panic(fmt.Sprintf("v23_syncbase_String contains non-UTF8 characters: %q", s))
+	}
 	x.p = C.CString(s)
 }
 
@@ -428,8 +435,16 @@
 	}
 	x.id.init(string(verror.ErrorID(err)))
 	x.actionCode = C.uint(verror.Action(err))
-	x.msg.init(err.Error())
-	x.stack.init(verror.Stack(err).String())
+	sErr := err.Error()
+	if !utf8.ValidString(sErr) {
+		vlog.Errorf("v23_syncbase_VError message has non-UTF8 characters: %q", sErr)
+	}
+	x.msg.init(escapeNonUnicode(sErr))
+	sStack := verror.Stack(err).String()
+	if !utf8.ValidString(sStack) {
+		vlog.Errorf("v23_syncbase_VError stack has non-UTF8 characters: %q", sStack)
+	}
+	x.stack.init(escapeNonUnicode(sStack))
 }
 
 func (x *C.v23_syncbase_VError) free() {
@@ -439,6 +454,17 @@
 	x.stack.free()
 }
 
+// escapeNonUnicode converts all non-Unicode characters to the Unicode "unknown
+// character".
+func escapeNonUnicode(s string) string {
+	return strings.Map(func(r rune) rune {
+		if r == utf8.RuneError {
+			return '\ufffd' // Unicode "unknown character".
+		}
+		return r
+	}, s)
+}
+
 ////////////////////////////////////////////////////////////
 // C.v23_syncbase_WatchChange