[gidl] Escape strings for HL/LLCPP
Also:
* Adding a constructor to StringPtr to match std::string construction
* Allowing logs to be emitted from the LLCPP conformance test
This change will support adding UTF8 validation to HLCPP and LLCPP (see
Iea42abd67dc928b4c1326b1a466befcb4b69226c).
Bug: 39686
Test: fx test fidl_llcpp_conformance_test
Change-Id: I9e05173ad551e780bf1301626f096803e5b871c3
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/392133
API-Review: Pascal Perez <pascallouis@google.com>
Commit-Queue: Pascal Perez <pascallouis@google.com>
Reviewed-by: Mitchell Kember <mkember@google.com>
Testability-Review: Mitchell Kember <mkember@google.com>
diff --git a/garnet/go/src/fidl/compiler/backend/common/strings.go b/garnet/go/src/fidl/compiler/backend/common/strings.go
index 6135b8e..dec2e46 100644
--- a/garnet/go/src/fidl/compiler/backend/common/strings.go
+++ b/garnet/go/src/fidl/compiler/backend/common/strings.go
@@ -10,3 +10,19 @@
s = strings.ReplaceAll(s, `'`, `\'`)
return fmt.Sprintf(`'%s'`, s)
}
+
+// PrintableASCIIRune reports whether r is a printable ASCII rune, i.e. in the
+// range 0x20 to 0x7E.
+func PrintableASCIIRune(r rune) bool {
+ return 0x20 <= r && r <= 0x7e
+}
+
+// PrintableASCII reports whether s is made of only printable ASCII runes.
+func PrintableASCII(s string) bool {
+ for _, r := range s {
+ if !PrintableASCIIRune(r) {
+ return false
+ }
+ }
+ return true
+}
diff --git a/garnet/go/src/fidl/compiler/backend/common/strings_test.go b/garnet/go/src/fidl/compiler/backend/common/strings_test.go
index d03a190..fcb1c96 100644
--- a/garnet/go/src/fidl/compiler/backend/common/strings_test.go
+++ b/garnet/go/src/fidl/compiler/backend/common/strings_test.go
@@ -46,3 +46,62 @@
}
}
}
+
+func TestPrintableASCIIRune(t *testing.T) {
+ // positive cases
+ printableRunes := []rune{
+ 'h',
+ 'e',
+ 'l',
+ '0',
+ rune(0x20),
+ rune(0x7e),
+ }
+ for _, r := range printableRunes {
+ if !PrintableASCIIRune(r) {
+ t.Errorf("expected %x to be a printable rune", r)
+ }
+ }
+
+ // negative cases
+ nonPrintableRunes := []rune{
+ rune(0x00),
+ rune(0x19),
+ rune(0x80),
+ rune(0x4242),
+ }
+ for _, r := range nonPrintableRunes {
+ if PrintableASCIIRune(r) {
+ t.Errorf("did not expect %x to be a printable rune", r)
+ }
+ }
+}
+
+func TestPrintableASCII(t *testing.T) {
+ // positive cases
+ printableStrings := []string{
+ "ahb",
+ "aeb",
+ "alb",
+ "a0b",
+ "a\x20b",
+ "a\x7eb",
+ }
+ for _, s := range printableStrings {
+ if !PrintableASCII(s) {
+ t.Errorf("expected %s to be a printable syring", s)
+ }
+ }
+
+ // negative cases
+ nonPrintableStrings := []string{
+ "a\x00b",
+ "a\x19b",
+ "a\x81b",
+ }
+ for _, s := range nonPrintableStrings {
+ if PrintableASCII(s) {
+ t.Errorf("did not expect %s to be a printable string", s)
+ }
+ }
+}
diff --git a/sdk/lib/fidl/cpp/fidl_cpp_base.api b/sdk/lib/fidl/cpp/fidl_cpp_base.api
index ea8f8bf..5fee118 100644
--- a/sdk/lib/fidl/cpp/fidl_cpp_base.api
+++ b/sdk/lib/fidl/cpp/fidl_cpp_base.api
@@ -6,7 +6,7 @@
"pkg/fidl_cpp_base/include/lib/fidl/cpp/encoder.h": "8fd3258444569fa8ca251f15c36bed48",
"pkg/fidl_cpp_base/include/lib/fidl/cpp/internal/logging.h": "6cc184bb613d6539ea5f568927ca06be",
"pkg/fidl_cpp_base/include/lib/fidl/cpp/object_coding.h": "d38c011c0a9cfdf7f2453676cb1f3f2f",
- "pkg/fidl_cpp_base/include/lib/fidl/cpp/string.h": "1748fadcfef3c5e5596b02599621d32b",
+ "pkg/fidl_cpp_base/include/lib/fidl/cpp/string.h": "2cf00b1ba5f68bcba03b03c4b1c7935d",
"pkg/fidl_cpp_base/include/lib/fidl/cpp/traits.h": "ca4dfa90b5f4961c81dbfddda683fe94",
"pkg/fidl_cpp_base/include/lib/fidl/cpp/transition.h": "ea5fd3c5abf19d39e0dda995f794d148",
"pkg/fidl_cpp_base/include/lib/fidl/cpp/vector.h": "12e15f28cbef68e04558bdb45d9ecabc"
diff --git a/sdk/lib/fidl/cpp/string.h b/sdk/lib/fidl/cpp/string.h
index dac3e36..7f7ef28 100644
--- a/sdk/lib/fidl/cpp/string.h
+++ b/sdk/lib/fidl/cpp/string.h
@@ -60,6 +60,8 @@
// Construct from string pointers
StringPtr(const char* value) : fit::optional<std::string>(value) {}
+ StringPtr(const char* value, size_t size)
+ : fit::optional<std::string>(std::string(value, size)) {}
StringPtr& operator=(const char* value) {
fit::optional<std::string>::operator=(value);
return *this;
@@ -172,7 +174,7 @@
const std::string& operator*() const { return str_; }
FIDL_FIT_OPTIONAL_DEPRECATED("use value_or(\"\")")
- operator const std::string &() const { return str_; }
+ operator const std::string&() const { return str_; }
private:
std::string str_;
diff --git a/src/lib/fidl/llcpp/tests/BUILD.gn b/src/lib/fidl/llcpp/tests/BUILD.gn
index f33e074..efae769 100644
--- a/src/lib/fidl/llcpp/tests/BUILD.gn
+++ b/src/lib/fidl/llcpp/tests/BUILD.gn
@@ -38,7 +38,7 @@
]
}
-unittest_package("fidl_llcpp_conformance_test") {
+test_package("fidl_llcpp_conformance_test") {
deps = [ ":fidl_llcpp_conformance_test_bin" ]
tests = [
diff --git a/src/lib/fidl/llcpp/tests/meta/fidl_llcpp_conformance_test.cmx b/src/lib/fidl/llcpp/tests/meta/fidl_llcpp_conformance_test.cmx
new file mode 100644
index 0000000..07de9f0
--- /dev/null
+++ b/src/lib/fidl/llcpp/tests/meta/fidl_llcpp_conformance_test.cmx
@@ -0,0 +1,11 @@
+{
+ "program": {
+ "binary": "test/fidl_llcpp_conformance_test"
+ },
+ "sandbox": {
+ "services": [
+ "fuchsia.logger.LogSink",
+ "fuchsia.process.Launcher"
+ ]
+ }
+}
diff --git a/tools/fidl/gidl/cpp/builder.go b/tools/fidl/gidl/cpp/builder.go
index b683c26..52211bd 100644
--- a/tools/fidl/gidl/cpp/builder.go
+++ b/tools/fidl/gidl/cpp/builder.go
@@ -5,10 +5,13 @@
package cpp
import (
+ "bytes"
+ "encoding/hex"
"fmt"
"strconv"
"strings"
+ fidlcommon "fidl/compiler/backend/common"
fidlir "fidl/compiler/backend/types"
gidlir "gidl/ir"
gidlmixer "gidl/mixer"
@@ -62,8 +65,24 @@
case float64:
return fmt.Sprintf("%g", value)
case string:
- // TODO(fxb/39686) Consider Go/C++ escape sequence differences
- return strconv.Quote(value)
+ if fidlcommon.PrintableASCII(value) {
+ return strconv.Quote(value)
+ }
+ var (
+ buf bytes.Buffer
+ src = []byte(value)
+ dstLen = hex.EncodedLen(len(src))
+ dst = make([]byte, dstLen)
+ )
+ hex.Encode(dst, src)
+ buf.WriteRune('"')
+ for i := 0; i < dstLen; i += 2 {
+ buf.WriteString("\\x")
+ buf.WriteByte(dst[i])
+ buf.WriteByte(dst[i+1])
+ }
+ buf.WriteRune('"')
+ return buf.String()
case gidlir.Record:
return b.visitRecord(value, decl.(gidlmixer.RecordDeclaration))
case []interface{}:
diff --git a/tools/fidl/gidl/rust/common.go b/tools/fidl/gidl/rust/common.go
index c019720..51ec6b8 100644
--- a/tools/fidl/gidl/rust/common.go
+++ b/tools/fidl/gidl/rust/common.go
@@ -17,15 +17,6 @@
gidlmixer "gidl/mixer"
)
-func isPrintableASCII(s string) bool {
- for _, r := range s {
- if r < 0x20 || r > 0x7e {
- return false
- }
- }
- return true
-}
-
func escapeStr(value string) string {
var (
buf bytes.Buffer
@@ -60,7 +51,7 @@
}
case string:
var expr string
- if isPrintableASCII(value) {
+ if fidlcommon.PrintableASCII(value) {
expr = fmt.Sprintf("String::from(%q)", value)
} else {
expr = fmt.Sprintf("std::str::from_utf8(b\"%s\").unwrap().to_string()", escapeStr(value))