diff options
author | Yury Delendik <ydelendik@mozilla.com> | 2018-08-31 09:26:23 -0500 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2018-08-31 07:26:23 -0700 |
commit | 5c01f256df98dfe94b0c62323f94c1bcdcc3679d (patch) | |
tree | 40c799005900da6e886da21c364a1f567c57d296 | |
parent | e4d014f4293e38f179354af7b049133679b256d8 (diff) | |
download | binaryen-5c01f256df98dfe94b0c62323f94c1bcdcc3679d.tar.gz binaryen-5c01f256df98dfe94b0c62323f94c1bcdcc3679d.tar.bz2 binaryen-5c01f256df98dfe94b0c62323f94c1bcdcc3679d.zip |
Escape name section ids in binary format reading/writing to be WebAssembly spec compatible. (#1646)
-rw-r--r-- | src/wasm-binary.h | 1 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 70 | ||||
-rw-r--r-- | test/complexBinaryNames.wasm | bin | 0 -> 73 bytes | |||
-rw-r--r-- | test/complexBinaryNames.wasm.fromBinary | 11 | ||||
-rw-r--r-- | test/complexTextNames.wast | 4 | ||||
-rw-r--r-- | test/complexTextNames.wast.from-wast | 10 | ||||
-rw-r--r-- | test/complexTextNames.wast.fromBinary | 11 | ||||
-rw-r--r-- | test/complexTextNames.wast.fromBinary.noDebugInfo | 11 |
8 files changed, 116 insertions, 2 deletions
diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 670084401..487979b3a 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -721,6 +721,7 @@ public: // helpers void writeInlineString(const char* name); + void writeEscapedName(const char* name); void writeInlineBuffer(const char* data, size_t size); struct Buffer { diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 935660d95..c6d1a6a60 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -452,13 +452,13 @@ void WasmBinaryWriter::writeNames() { for (auto& import : wasm->imports) { if (import->kind == ExternalKind::Function) { o << U32LEB(emitted); - writeInlineString(import->name.str); + writeEscapedName(import->name.str); emitted++; } } for (auto& curr : wasm->functions) { o << U32LEB(emitted); - writeInlineString(curr->name.str); + writeEscapedName(curr->name.str); emitted++; } assert(emitted == mappedFunctions.size()); @@ -565,6 +565,35 @@ void WasmBinaryWriter::writeInlineString(const char* name) { } } +static bool isHexDigit(char ch) { + return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F'); +} + +static int decodeHexNibble(char ch) { + return ch <= '9' ? ch & 15 : (ch & 15) + 9; +} + +void WasmBinaryWriter::writeEscapedName(const char* name) { + if (!strpbrk(name, "\\")) { + writeInlineString(name); + return; + } + // decode escaped by escapeName (see below) function names + std::string unescaped; + int32_t size = strlen(name); + for (int32_t i = 0; i < size;) { + char ch = name[i++]; + // support only `\xx` escapes; ignore invalid or unsupported escapes + if (ch != '\\' || i + 1 >= size || !isHexDigit(name[i]) || !isHexDigit(name[i + 1])) { + unescaped.push_back(ch); + continue; + } + unescaped.push_back(char((decodeHexNibble(name[i]) << 4) | decodeHexNibble(name[i + 1]))); + i += 2; + } + writeInlineString(unescaped.c_str()); +} + void WasmBinaryWriter::writeInlineBuffer(const char* data, size_t size) { o << U32LEB(size); for (size_t i = 0; i < size; i++) { @@ -1515,6 +1544,42 @@ void WasmBinaryBuilder::readTableElements() { } } +static bool isIdChar(char ch) { + return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || + ch == '!' || ch == '#' || ch == '$' || ch == '%' || ch == '&' || ch == '\'' || ch == '*' || + ch == '+' || ch == '-' || ch == '.' || ch == '/' || ch == ':' || ch == '<' || ch == '=' || + ch == '>' || ch == '?' || ch == '@' || ch == '^' || ch == '_' || ch == '`' || ch == '|' || + ch == '~'; +} + +static char formatNibble(int nibble) { + return nibble < 10 ? '0' + nibble : 'a' - 10 + nibble; +} + +static void escapeName(Name &name) { + bool allIdChars = true; + for (const char *p = name.str; allIdChars && *p; p++) { + allIdChars = isIdChar(*p); + } + if (allIdChars) { + return; + } + // encode name, if at least one non-idchar (per WebAssembly spec) was found + std::string escaped; + for (const char *p = name.str; *p; p++) { + char ch = *p; + if (isIdChar(ch)) { + escaped.push_back(ch); + continue; + } + // replace non-idchar with `\xx` escape + escaped.push_back('\\'); + escaped.push_back(formatNibble(ch >> 4)); + escaped.push_back(formatNibble(ch & 15)); + } + name = escaped; +} + void WasmBinaryBuilder::readNames(size_t payloadLen) { if (debug) std::cerr << "== readNames" << std::endl; auto sectionPos = pos; @@ -1533,6 +1598,7 @@ void WasmBinaryBuilder::readNames(size_t payloadLen) { for (size_t i = 0; i < num; i++) { auto index = getU32LEB(); auto rawName = getInlineString(); + escapeName(rawName); auto name = rawName; // De-duplicate names by appending .1, .2, etc. for (int i = 1; !usedNames.insert(name).second; ++i) { diff --git a/test/complexBinaryNames.wasm b/test/complexBinaryNames.wasm Binary files differnew file mode 100644 index 000000000..a29653c86 --- /dev/null +++ b/test/complexBinaryNames.wasm diff --git a/test/complexBinaryNames.wasm.fromBinary b/test/complexBinaryNames.wasm.fromBinary new file mode 100644 index 000000000..e50a9134d --- /dev/null +++ b/test/complexBinaryNames.wasm.fromBinary @@ -0,0 +1,11 @@ +(module + (type $0 (func)) + (export "$zoo (.bar)" (func $1)) + (func $foo\20\28.bar\29 (; 0 ;) (type $0) + (nop) + ) + (func $1 (; 1 ;) (type $0) + (call $foo\20\28.bar\29) + ) +) + diff --git a/test/complexTextNames.wast b/test/complexTextNames.wast new file mode 100644 index 000000000..f27ca56b3 --- /dev/null +++ b/test/complexTextNames.wast @@ -0,0 +1,4 @@ +(module + (func $foo\20\28.bar\29) + (func "$zoo (.bar)" (call $foo\20\28.bar\29)) +) diff --git a/test/complexTextNames.wast.from-wast b/test/complexTextNames.wast.from-wast new file mode 100644 index 000000000..7ea6975f6 --- /dev/null +++ b/test/complexTextNames.wast.from-wast @@ -0,0 +1,10 @@ +(module + (type $0 (func)) + (export "$zoo (.bar)" (func $1)) + (func $foo\20\28.bar\29 (; 0 ;) (type $0) + (nop) + ) + (func $1 (; 1 ;) (type $0) + (call $foo\20\28.bar\29) + ) +) diff --git a/test/complexTextNames.wast.fromBinary b/test/complexTextNames.wast.fromBinary new file mode 100644 index 000000000..e50a9134d --- /dev/null +++ b/test/complexTextNames.wast.fromBinary @@ -0,0 +1,11 @@ +(module + (type $0 (func)) + (export "$zoo (.bar)" (func $1)) + (func $foo\20\28.bar\29 (; 0 ;) (type $0) + (nop) + ) + (func $1 (; 1 ;) (type $0) + (call $foo\20\28.bar\29) + ) +) + diff --git a/test/complexTextNames.wast.fromBinary.noDebugInfo b/test/complexTextNames.wast.fromBinary.noDebugInfo new file mode 100644 index 000000000..ad2a43c34 --- /dev/null +++ b/test/complexTextNames.wast.fromBinary.noDebugInfo @@ -0,0 +1,11 @@ +(module + (type $0 (func)) + (export "$zoo (.bar)" (func $1)) + (func $0 (; 0 ;) (type $0) + (nop) + ) + (func $1 (; 1 ;) (type $0) + (call $0) + ) +) + |