Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check malformed mutability on imported globals #6679

Merged
merged 4 commits into from
Jun 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions scripts/test/shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,6 @@ def get_tests(test_dir, extensions=[], recursive=False):
# expected-output/ if any.
SPEC_TESTS_TO_SKIP = [
# Malformed module accepted
'globals.wast',
'binary-leb128.wast',
'utf8-custom-section-id.wast',
'utf8-import-field.wast',
Expand All @@ -417,9 +416,6 @@ def get_tests(test_dir, extensions=[], recursive=False):
'type.wast',
'unreached-invalid.wast',

# WAST parser error
'binary.wast',

# Test invalid
'elem.wast',
]
Expand Down
2 changes: 2 additions & 0 deletions src/parser/wast-parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ Result<WASTModule> wastModule(Lexer& in, bool maybeInvalid = false) {
if (!in.takeSExprStart("module"sv)) {
return in.err("expected module");
}
// TODO: use ID?
[[maybe_unused]] auto id = in.takeID();
QuotedModuleType type;
if (in.takeKeyword("quote"sv)) {
type = QuotedModuleType::Text;
Expand Down
2 changes: 1 addition & 1 deletion src/wasm-binary.h
Original file line number Diff line number Diff line change
Expand Up @@ -1583,7 +1583,7 @@ class WasmBinaryReader {
void readVars();

std::map<Export*, Index> exportIndices;
std::vector<Export*> exportOrder;
std::vector<std::unique_ptr<Export>> exportOrder;
void readExports();

// The strings in the strings section (which are referred to by StringConst).
Expand Down
36 changes: 26 additions & 10 deletions src/wasm/wasm-binary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "ir/type-updating.h"
#include "support/bits.h"
#include "support/debug.h"
#include "support/stdckdint.h"
#include "support/string.h"
#include "wasm-binary.h"
#include "wasm-debug.h"
Expand Down Expand Up @@ -2583,6 +2584,9 @@ void WasmBinaryReader::readImports() {
Name name(std::string("gimport$") + std::to_string(globalCounter++));
auto type = getConcreteType();
auto mutable_ = getU32LEB();
if (mutable_ & ~1) {
throwError("Global mutability must be 0 or 1");
}
auto curr =
builder.makeGlobal(name,
type,
Expand Down Expand Up @@ -2681,10 +2685,10 @@ void WasmBinaryReader::readFunctions() {
}
endOfFunction = pos + size;

auto* func = new Function;
auto func = std::make_unique<Function>();
func->name = Name::fromInt(i);
func->type = getTypeByFunctionIndex(numImports + i);
currFunction = func;
currFunction = func.get();

if (DWARF) {
func->funcLocation = BinaryLocations::FunctionLocations{
Expand Down Expand Up @@ -2748,21 +2752,29 @@ void WasmBinaryReader::readFunctions() {
}
}

TypeUpdating::handleNonDefaultableLocals(func, wasm);
TypeUpdating::handleNonDefaultableLocals(func.get(), wasm);

std::swap(func->epilogLocation, debugLocation);
currFunction = nullptr;
debugLocation.clear();
wasm.addFunction(func);
wasm.addFunction(std::move(func));
}
BYN_TRACE(" end function bodies\n");
}

void WasmBinaryReader::readVars() {
uint32_t totalVars = 0;
size_t numLocalTypes = getU32LEB();
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");
}
auto type = getConcreteType();

while (num > 0) {
currFunction->vars.push_back(type);
num--;
Expand All @@ -2777,15 +2789,15 @@ void WasmBinaryReader::readExports() {
std::unordered_set<Name> names;
for (size_t i = 0; i < num; i++) {
BYN_TRACE("read one\n");
auto curr = new Export;
auto curr = std::make_unique<Export>();
curr->name = getInlineString();
if (!names.emplace(curr->name).second) {
throwError("duplicate export name");
}
curr->kind = (ExternalKind)getU32LEB();
auto index = getU32LEB();
exportIndices[curr] = index;
exportOrder.push_back(curr);
exportIndices[curr.get()] = index;
exportOrder.push_back(std::move(curr));
}
}

Expand Down Expand Up @@ -3228,6 +3240,10 @@ void WasmBinaryReader::validateBinary() {
if (hasDataCount && wasm.dataSegments.size() != dataCount) {
throwError("Number of segments does not agree with DataCount section");
}

if (functionTypes.size() != wasm.functions.size()) {
throwError("function section without code section");
}
}

void WasmBinaryReader::processNames() {
Expand All @@ -3237,8 +3253,8 @@ void WasmBinaryReader::processNames() {
wasm.start = getFunctionName(startIndex);
}

for (auto* curr : exportOrder) {
auto index = exportIndices[curr];
for (auto& curr : exportOrder) {
auto index = exportIndices[curr.get()];
switch (curr->kind) {
case ExternalKind::Function: {
curr->value = getFunctionName(index);
Expand All @@ -3259,7 +3275,7 @@ void WasmBinaryReader::processNames() {
default:
throwError("bad export kind");
}
wasm.addExport(curr);
wasm.addExport(std::move(curr));
}

for (auto& [index, refs] : functionRefs) {
Expand Down
191 changes: 0 additions & 191 deletions test/spec/binary.wast
Original file line number Diff line number Diff line change
Expand Up @@ -138,197 +138,6 @@
"zero flag expected"
)

;; memory.grow reserved byte equal to zero.
(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\01\04\01\60\00\00" ;; Type section
"\03\02\01\00" ;; Function section
"\05\03\01\00\00" ;; Memory section
"\0a\09\01" ;; Code section

;; function 0
"\07\00"
"\41\00" ;; i32.const 0
"\40" ;; memory.grow
"\01" ;; memory.grow reserved byte is not equal to zero!
"\1a" ;; drop
"\0b" ;; end
)
"zero flag expected"
)

;; memory.grow reserved byte should not be a "long" LEB128 zero.
(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\01\04\01\60\00\00" ;; Type section
"\03\02\01\00" ;; Function section
"\05\03\01\00\00" ;; Memory section
"\0a\0a\01" ;; Code section

;; function 0
"\08\00"
"\41\00" ;; i32.const 0
"\40" ;; memory.grow
"\80\00" ;; memory.grow reserved byte
"\1a" ;; drop
"\0b" ;; end
)
"zero flag expected"
)

;; Same as above for 3, 4, and 5-byte zero encodings.
(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\01\04\01\60\00\00" ;; Type section
"\03\02\01\00" ;; Function section
"\05\03\01\00\00" ;; Memory section
"\0a\0b\01" ;; Code section

;; function 0
"\09\00"
"\41\00" ;; i32.const 0
"\40" ;; memory.grow
"\80\80\00" ;; memory.grow reserved byte
"\1a" ;; drop
"\0b" ;; end
)
"zero flag expected"
)

(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\01\04\01\60\00\00" ;; Type section
"\03\02\01\00" ;; Function section
"\05\03\01\00\00" ;; Memory section
"\0a\0c\01" ;; Code section

;; function 0
"\0a\00"
"\41\00" ;; i32.const 0
"\40" ;; memory.grow
"\80\80\80\00" ;; memory.grow reserved byte
"\1a" ;; drop
"\0b" ;; end
)
"zero flag expected"
)

(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\01\04\01\60\00\00" ;; Type section
"\03\02\01\00" ;; Function section
"\05\03\01\00\00" ;; Memory section
"\0a\0d\01" ;; Code section

;; function 0
"\0b\00"
"\41\00" ;; i32.const 0
"\40" ;; memory.grow
"\80\80\80\80\00" ;; memory.grow reserved byte
"\1a" ;; drop
"\0b" ;; end
)
"zero flag expected"
)

;; memory.size reserved byte equal to zero.
(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\01\04\01\60\00\00" ;; Type section
"\03\02\01\00" ;; Function section
"\05\03\01\00\00" ;; Memory section
"\0a\07\01" ;; Code section

;; function 0
"\05\00"
"\3f" ;; memory.size
"\01" ;; memory.size reserved byte is not equal to zero!
"\1a" ;; drop
"\0b" ;; end
)
"zero flag expected"
)

;; memory.size reserved byte should not be a "long" LEB128 zero.
(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\01\04\01\60\00\00" ;; Type section
"\03\02\01\00" ;; Function section
"\05\03\01\00\00" ;; Memory section
"\0a\08\01" ;; Code section

;; function 0
"\06\00"
"\3f" ;; memory.size
"\80\00" ;; memory.size reserved byte
"\1a" ;; drop
"\0b" ;; end
)
"zero flag expected"
)

;; Same as above for 3, 4, and 5-byte zero encodings.
(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\01\04\01\60\00\00" ;; Type section
"\03\02\01\00" ;; Function section
"\05\03\01\00\00" ;; Memory section
"\0a\09\01" ;; Code section

;; function 0
"\07\00"
"\3f" ;; memory.size
"\80\80\00" ;; memory.size reserved byte
"\1a" ;; drop
"\0b" ;; end
)
"zero flag expected"
)

(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\01\04\01\60\00\00" ;; Type section
"\03\02\01\00" ;; Function section
"\05\03\01\00\00" ;; Memory section
"\0a\0a\01" ;; Code section

;; function 0
"\08\00"
"\3f" ;; memory.size
"\80\80\80\00" ;; memory.size reserved byte
"\1a" ;; drop
"\0b" ;; end
)
"zero flag expected"
)

(assert_malformed
(module binary
"\00asm" "\01\00\00\00"
"\01\04\01\60\00\00" ;; Type section
"\03\02\01\00" ;; Function section
"\05\03\01\00\00" ;; Memory section
"\0a\0b\01" ;; Code section

;; function 0
"\09\00"
"\3f" ;; memory.size
"\80\80\80\80\00" ;; memory.size reserved byte
"\1a" ;; drop
"\0b" ;; end
)
"zero flag expected"
)

;; No more than 2^32 locals.
(assert_malformed
(module binary
Expand Down
Loading