Skip to content

Commit 0ec9ddf

Browse files
authored
Proper Asyncify list name handling (#2275)
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
1 parent cbcca4c commit 0ec9ddf

File tree

4 files changed

+50
-0
lines changed

4 files changed

+50
-0
lines changed

src/passes/Asyncify.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,9 @@ struct Asyncify : public Pass {
10431043
String::Split whitelist(
10441044
runner->options.getArgumentOrDefault("asyncify-whitelist", ""), ",");
10451045

1046+
blacklist = handleBracketingOperators(blacklist);
1047+
whitelist = handleBracketingOperators(whitelist);
1048+
10461049
// The lists contain human-readable strings. Turn them into the internal
10471050
// escaped names for later comparisons
10481051
auto processList = [module](String::Split& list, const std::string& which) {

src/support/string.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ namespace String {
3131
// Creates a vector of the split parts of a string, by a delimiter.
3232
class Split : public std::vector<std::string> {
3333
public:
34+
Split() = default;
35+
3436
Split(const std::string& input, const std::string& delim) {
3537
size_t lastEnd = 0;
3638
while (lastEnd < input.size()) {
@@ -44,6 +46,46 @@ class Split : public std::vector<std::string> {
4446
}
4547
};
4648

49+
// Handles bracketing in a list initially split by ",", but the list may
50+
// contain nested ","s. For example,
51+
// void foo(int, double)
52+
// must be kept together because of the "(". Likewise, "{", "<", "[" are
53+
// handled.
54+
inline String::Split handleBracketingOperators(String::Split split) {
55+
String::Split ret;
56+
std::string last;
57+
int nesting = 0;
58+
auto handlePart = [&](std::string part) {
59+
if (part.empty()) {
60+
return;
61+
}
62+
for (const char c : part) {
63+
if (c == '(' || c == '<' || c == '[' || c == '{') {
64+
nesting++;
65+
} else if (c == ')' || c == '>' || c == ']' || c == '}') {
66+
nesting--;
67+
}
68+
}
69+
if (last.empty()) {
70+
last = part;
71+
} else {
72+
last += ',' + part;
73+
}
74+
if (nesting == 0) {
75+
ret.push_back(last);
76+
last.clear();
77+
}
78+
};
79+
for (auto& part : split) {
80+
handlePart(part);
81+
}
82+
handlePart("");
83+
if (nesting != 0) {
84+
Fatal() << "Asyncify: failed to parse lists";
85+
}
86+
return ret;
87+
}
88+
4789
// Does a simple wildcard match between a pattern and a value. Currently
4890
// supports a '*' at the end of the pattern.
4991
inline bool wildcardMatch(const std::string& pattern,

test/unit/input/asyncify-pure.wast

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,5 +55,8 @@
5555
(call $main)
5656
(call $print (i32.const 500))
5757
)
58+
;; interesting escaped name
59+
(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)
60+
)
5861
)
5962

test/unit/test_asyncify.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ def test_asyncify_list_bad(self):
3535
('--pass-arg=asyncify-whitelist@nonexistent', 'nonexistent'),
3636
('--pass-arg=asyncify-blacklist@main', None),
3737
('--pass-arg=asyncify-whitelist@main', None),
38+
('--pass-arg=asyncify-whitelist@main', None),
39+
('--pass-arg=asyncify-whitelist@DOS_ReadFile(unsigned short, unsigned char*, unsigned short*, bool)', None),
3840
]:
3941
print(arg, warning)
4042
err = run_process(WASM_OPT + [self.input_path('asyncify-pure.wast'), '--asyncify', arg], stdout=subprocess.PIPE, stderr=subprocess.PIPE).stderr.strip()

0 commit comments

Comments
 (0)