summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/wasm-binary.h1
-rw-r--r--src/wasm/wasm-binary.cpp70
-rw-r--r--test/complexBinaryNames.wasmbin0 -> 73 bytes
-rw-r--r--test/complexBinaryNames.wasm.fromBinary11
-rw-r--r--test/complexTextNames.wast4
-rw-r--r--test/complexTextNames.wast.from-wast10
-rw-r--r--test/complexTextNames.wast.fromBinary11
-rw-r--r--test/complexTextNames.wast.fromBinary.noDebugInfo11
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
new file mode 100644
index 000000000..a29653c86
--- /dev/null
+++ b/test/complexBinaryNames.wasm
Binary files differ
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)
+ )
+)
+