Skip to content

Commit

Permalink
Proper Asyncify list name handling (#2275)
Browse files Browse the repository at this point in the history
The lists are comma separated, but the names can have internal commas since they are human-readable. This adds awareness of bracketing things, so void foo(int, double) is parsed as a single function name, properly.

Helps emscripten-core/emscripten#9128
  • Loading branch information
kripken authored Aug 1, 2019
1 parent cbcca4c commit 0ec9ddf
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/passes/Asyncify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1043,6 +1043,9 @@ struct Asyncify : public Pass {
String::Split whitelist(
runner->options.getArgumentOrDefault("asyncify-whitelist", ""), ",");

blacklist = handleBracketingOperators(blacklist);
whitelist = handleBracketingOperators(whitelist);

// The lists contain human-readable strings. Turn them into the internal
// escaped names for later comparisons
auto processList = [module](String::Split& list, const std::string& which) {
Expand Down
42 changes: 42 additions & 0 deletions src/support/string.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ namespace String {
// Creates a vector of the split parts of a string, by a delimiter.
class Split : public std::vector<std::string> {
public:
Split() = default;

Split(const std::string& input, const std::string& delim) {
size_t lastEnd = 0;
while (lastEnd < input.size()) {
Expand All @@ -44,6 +46,46 @@ class Split : public std::vector<std::string> {
}
};

// Handles bracketing in a list initially split by ",", but the list may
// contain nested ","s. For example,
// void foo(int, double)
// must be kept together because of the "(". Likewise, "{", "<", "[" are
// handled.
inline String::Split handleBracketingOperators(String::Split split) {
String::Split ret;
std::string last;
int nesting = 0;
auto handlePart = [&](std::string part) {
if (part.empty()) {
return;
}
for (const char c : part) {
if (c == '(' || c == '<' || c == '[' || c == '{') {
nesting++;
} else if (c == ')' || c == '>' || c == ']' || c == '}') {
nesting--;
}
}
if (last.empty()) {
last = part;
} else {
last += ',' + part;
}
if (nesting == 0) {
ret.push_back(last);
last.clear();
}
};
for (auto& part : split) {
handlePart(part);
}
handlePart("");
if (nesting != 0) {
Fatal() << "Asyncify: failed to parse lists";
}
return ret;
}

// Does a simple wildcard match between a pattern and a value. Currently
// supports a '*' at the end of the pattern.
inline bool wildcardMatch(const std::string& pattern,
Expand Down
3 changes: 3 additions & 0 deletions test/unit/input/asyncify-pure.wast
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,8 @@
(call $main)
(call $print (i32.const 500))
)
;; interesting escaped name
(func $DOS_ReadFile\28unsigned\20short\2c\20unsigned\20char*\2c\20unsigned\20short*\2c\20bool\29 (param $0 i32) (param $1 i32) (param $2 i32) (param $3 i32)
)
)

2 changes: 2 additions & 0 deletions test/unit/test_asyncify.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ def test_asyncify_list_bad(self):
('--pass-arg=asyncify-whitelist@nonexistent', 'nonexistent'),
('--pass-arg=asyncify-blacklist@main', None),
('--pass-arg=asyncify-whitelist@main', None),
('--pass-arg=asyncify-whitelist@main', None),
('--pass-arg=asyncify-whitelist@DOS_ReadFile(unsigned short, unsigned char*, unsigned short*, bool)', None),
]:
print(arg, warning)
err = run_process(WASM_OPT + [self.input_path('asyncify-pure.wast'), '--asyncify', arg], stdout=subprocess.PIPE, stderr=subprocess.PIPE).stderr.strip()
Expand Down

0 comments on commit 0ec9ddf

Please sign in to comment.