summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/wasm/wasm-binary.cpp20
-rw-r--r--test/unit/test_web_limitations.py16
2 files changed, 30 insertions, 6 deletions
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp
index 3bb33529b..466771803 100644
--- a/src/wasm/wasm-binary.cpp
+++ b/src/wasm/wasm-binary.cpp
@@ -472,6 +472,10 @@ void WasmBinaryWriter::writeFunctions() {
std::cerr << "Some VMs may not accept this binary because it has a large "
<< "number of parameters in function " << func->name << ".\n";
}
+ if (func->getNumLocals() > WebLimitations::MaxFunctionLocals) {
+ std::cerr << "Some VMs may not accept this binary because it has a large "
+ << "number of locals in function " << func->name << ".\n";
+ }
});
finishSection(sectionStart);
}
@@ -2722,16 +2726,20 @@ void WasmBinaryReader::readFunctions() {
void WasmBinaryReader::readVars() {
uint32_t totalVars = 0;
size_t numLocalTypes = getU32LEB();
+ // Use a SmallVector as in the common (MVP) case there are only 4 possible
+ // types.
+ SmallVector<std::pair<uint32_t, Type>, 4> decodedVars;
+ decodedVars.reserve(numLocalTypes);
for (size_t t = 0; t < numLocalTypes; t++) {
auto num = getU32LEB();
- // The core spec allows up to 2^32 locals, but to avoid allocation failures,
- // we additionally impose a much smaller limit, matching the JS embedding.
- if (std::ckd_add(&totalVars, totalVars, num) ||
- totalVars > WebLimitations::MaxFunctionLocals) {
- throwError("too many locals");
+ if (std::ckd_add(&totalVars, totalVars, num)) {
+ throwError("unaddressable number of locals");
}
auto type = getConcreteType();
-
+ decodedVars.emplace_back(num, type);
+ }
+ currFunction->vars.reserve(totalVars);
+ for (auto [num, type] : decodedVars) {
while (num > 0) {
currFunction->vars.push_back(type);
num--;
diff --git a/test/unit/test_web_limitations.py b/test/unit/test_web_limitations.py
index 6359390f9..921e02e95 100644
--- a/test/unit/test_web_limitations.py
+++ b/test/unit/test_web_limitations.py
@@ -20,3 +20,19 @@ class WebLimitations(utils.BinaryenTestCase):
input=module, capture_output=True)
self.assertIn('Some VMs may not accept this binary because it has a large number of parameters in function foo.',
p.stderr)
+
+ def test_many_locals(self):
+ """Test that we warn on large numbers of locals, which Web VMs
+ disallow."""
+
+ params = '(local i32) ' * 50_001
+ module = '''
+ (module
+ (func $foo %s
+ )
+ )
+ ''' % params
+ p = shared.run_process(shared.WASM_OPT + ['-o', os.devnull],
+ input=module, capture_output=True)
+ self.assertIn('Some VMs may not accept this binary because it has a large number of locals in function foo.',
+ p.stderr)