summaryrefslogtreecommitdiff
path: root/src/wasm/wasm-binary.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm/wasm-binary.cpp')
-rw-r--r--src/wasm/wasm-binary.cpp70
1 files changed, 68 insertions, 2 deletions
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) {