[wasm] Allow for arbitrarily long error messages
We currently have a fixed limit of 256 characters for error messages generated in the decoder. However, we sometimes embed names in it, which makes it easy to generate a crash by using long names (e.g. for exports) in invalid wasm modules. This CL fixes this by switching to a stream based interface, allowing to pass arbitrary objects to be printed. With this interface, we can easily limit the length of output later. R=titzer@chromium.org Bug: chromium:740023 Change-Id: I2848c31c63a015157e2a3a9458b54e523060cd69 Reviewed-on: https://chromium-review.googlesource.com/565282 Reviewed-by: Ben Titzer <titzer@chromium.org> Commit-Queue: Clemens Hammacher <clemensh@chromium.org> Cr-Commit-Position: refs/heads/master@{#46860}
This commit is contained in:
parent
620b544ddf
commit
072d0e3eb6
@ -37,6 +37,34 @@ namespace wasm {
|
||||
// a buffer of bytes.
|
||||
class Decoder {
|
||||
public:
|
||||
class ErrorFormatter {
|
||||
public:
|
||||
// Allow move, but nothing else.
|
||||
MOVE_ONLY_NO_DEFAULT_CONSTRUCTOR(ErrorFormatter);
|
||||
~ErrorFormatter() {
|
||||
if (!decoder_) return;
|
||||
DCHECK(decoder_->ok());
|
||||
|
||||
decoder_->error_offset_ = decoder_->pc_offset(pc_);
|
||||
decoder_->error_msg_ = message_builder_.str();
|
||||
decoder_->onFirstError();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ErrorFormatter& operator<<(T&& arg) {
|
||||
if (decoder_) message_builder_ << std::forward<T>(arg);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Decoder;
|
||||
std::ostringstream message_builder_;
|
||||
const byte* pc_;
|
||||
Decoder* decoder_;
|
||||
ErrorFormatter(const byte* pc, Decoder* decoder)
|
||||
: pc_(pc), decoder_(decoder) {}
|
||||
};
|
||||
|
||||
Decoder(const byte* start, const byte* end, uint32_t buffer_offset = 0)
|
||||
: start_(start), pc_(start), end_(end), buffer_offset_(buffer_offset) {}
|
||||
Decoder(const byte* start, const byte* pc, const byte* end,
|
||||
@ -48,7 +76,7 @@ class Decoder {
|
||||
inline bool check(const byte* pc, uint32_t length, const char* msg) {
|
||||
DCHECK_LE(start_, pc);
|
||||
if (V8_UNLIKELY(pc + length > end_)) {
|
||||
error(pc, msg);
|
||||
error(pc) << msg;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -125,13 +153,13 @@ class Decoder {
|
||||
}
|
||||
|
||||
// Reads a LEB128 variable-length unsigned 32-bit integer and advances {pc_}.
|
||||
uint32_t consume_u32v(const char* name = nullptr) {
|
||||
uint32_t consume_u32v(const char* name = "uint32_t") {
|
||||
uint32_t length = 0;
|
||||
return read_leb<uint32_t, true, true, true>(pc_, &length, name);
|
||||
}
|
||||
|
||||
// Reads a LEB128 variable-length signed 32-bit integer and advances {pc_}.
|
||||
int32_t consume_i32v(const char* name = nullptr) {
|
||||
int32_t consume_i32v(const char* name = "int32_t") {
|
||||
uint32_t length = 0;
|
||||
return read_leb<int32_t, true, true, true>(pc_, &length, name);
|
||||
}
|
||||
@ -151,40 +179,27 @@ class Decoder {
|
||||
bool checkAvailable(int size) {
|
||||
intptr_t pc_overflow_value = std::numeric_limits<intptr_t>::max() - size;
|
||||
if (size < 0 || (intptr_t)pc_ > pc_overflow_value) {
|
||||
errorf(pc_, "reading %d bytes would underflow/overflow", size);
|
||||
error(pc_) << "reading " << size << " bytes would underflow/overflow";
|
||||
return false;
|
||||
} else if (pc_ < start_ || end_ < (pc_ + size)) {
|
||||
errorf(pc_, "expected %d bytes, fell off end", size);
|
||||
error(pc_) << "expected " << size << " bytes, fell off end";
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void error(const char* msg) { errorf(pc_, "%s", msg); }
|
||||
|
||||
void error(const byte* pc, const char* msg) { errorf(pc, "%s", msg); }
|
||||
|
||||
// Sets internal error state.
|
||||
void PRINTF_FORMAT(3, 4) errorf(const byte* pc, const char* format, ...) {
|
||||
// ErrorFormatter sets internal error state in its destructor.
|
||||
ErrorFormatter error(const byte* pc = nullptr) {
|
||||
// Only report the first error.
|
||||
if (!ok()) return;
|
||||
if (!ok()) return {nullptr, nullptr};
|
||||
#if DEBUG
|
||||
if (FLAG_wasm_break_on_decoder_error) {
|
||||
base::OS::DebugBreak();
|
||||
}
|
||||
#endif
|
||||
constexpr int kMaxErrorMsg = 256;
|
||||
EmbeddedVector<char, kMaxErrorMsg> buffer;
|
||||
va_list arguments;
|
||||
va_start(arguments, format);
|
||||
int len = VSNPrintF(buffer, format, arguments);
|
||||
CHECK_LT(0, len);
|
||||
va_end(arguments);
|
||||
error_msg_.assign(buffer.start(), len);
|
||||
DCHECK_GE(pc, start_);
|
||||
error_offset_ = static_cast<uint32_t>(pc - start_) + buffer_offset_;
|
||||
onFirstError();
|
||||
|
||||
return {pc ? pc : pc_, this};
|
||||
}
|
||||
|
||||
// Behavior triggered on first error, overridden in subclasses.
|
||||
@ -233,9 +248,11 @@ class Decoder {
|
||||
|
||||
const byte* start() const { return start_; }
|
||||
const byte* pc() const { return pc_; }
|
||||
uint32_t pc_offset() const {
|
||||
return static_cast<uint32_t>(pc_ - start_) + buffer_offset_;
|
||||
uint32_t pc_offset(const byte* pc) const {
|
||||
DCHECK_GE(pc, start_);
|
||||
return static_cast<uint32_t>(pc - start_) + buffer_offset_;
|
||||
}
|
||||
uint32_t pc_offset() const { return pc_offset(pc_); }
|
||||
uint32_t buffer_offset() const { return buffer_offset_; }
|
||||
// Takes an offset relative to the module start and returns an offset relative
|
||||
// to the current buffer of the decoder.
|
||||
@ -318,7 +335,7 @@ class Decoder {
|
||||
*length = byte_index + (at_end ? 0 : 1);
|
||||
if (checked && (at_end || (b & 0x80))) {
|
||||
TRACE_IF(trace, at_end ? "<end> " : "<length overflow> ");
|
||||
errorf(pc, "expected %s", name);
|
||||
error(pc) << "expected " << name;
|
||||
result = 0;
|
||||
}
|
||||
if (is_last_byte) {
|
||||
@ -338,7 +355,7 @@ class Decoder {
|
||||
if (!checked) {
|
||||
DCHECK(valid_extra_bits);
|
||||
} else if (!valid_extra_bits) {
|
||||
error(pc, "extra bits in varint");
|
||||
error(pc) << "extra bits in varint";
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
|
@ -101,11 +101,11 @@ struct BlockTypeOperand {
|
||||
} else {
|
||||
// Handle multi-value blocks.
|
||||
if (!CHECKED_COND(FLAG_experimental_wasm_mv)) {
|
||||
decoder->error(pc + 1, "invalid block arity > 1");
|
||||
decoder->error(pc + 1) << "invalid block arity > 1";
|
||||
return;
|
||||
}
|
||||
if (!CHECKED_COND(val == kMultivalBlock)) {
|
||||
decoder->error(pc + 1, "invalid block type");
|
||||
decoder->error(pc + 1) << "invalid block type";
|
||||
return;
|
||||
}
|
||||
// Decode and check the types vector of the block.
|
||||
@ -123,7 +123,7 @@ struct BlockTypeOperand {
|
||||
val = decoder->read_u8<checked>(pc + offset, "block type");
|
||||
decode_local_type(val, &type);
|
||||
if (!CHECKED_COND(type != kWasmStmt)) {
|
||||
decoder->error(pc + offset, "invalid block type");
|
||||
decoder->error(pc + offset) << "invalid block type";
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -187,8 +187,8 @@ struct CallIndirectOperand {
|
||||
index = decoder->read_u32v<checked>(pc + 1, &len, "signature index");
|
||||
table_index = decoder->read_u8<checked>(pc + 1 + len, "table index");
|
||||
if (!CHECKED_COND(table_index == 0)) {
|
||||
decoder->errorf(pc + 1 + len, "expected table index 0, found %u",
|
||||
table_index);
|
||||
decoder->error(pc + 1 + len)
|
||||
<< "expected table index 0, found " << table_index;
|
||||
}
|
||||
length = 1 + len;
|
||||
}
|
||||
@ -211,7 +211,7 @@ struct MemoryIndexOperand {
|
||||
inline MemoryIndexOperand(Decoder* decoder, const byte* pc) {
|
||||
index = decoder->read_u8<checked>(pc + 1, "memory index");
|
||||
if (!CHECKED_COND(index == 0)) {
|
||||
decoder->errorf(pc + 1, "expected memory index 0, found %u", index);
|
||||
decoder->error(pc + 1) << "expected memory index 0, found " << index;
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -279,10 +279,9 @@ struct MemoryAccessOperand {
|
||||
alignment =
|
||||
decoder->read_u32v<checked>(pc + 1, &alignment_length, "alignment");
|
||||
if (!CHECKED_COND(alignment <= max_alignment)) {
|
||||
decoder->errorf(pc + 1,
|
||||
"invalid alignment; expected maximum alignment is %u, "
|
||||
"actual alignment is %u",
|
||||
max_alignment, alignment);
|
||||
decoder->error(pc + 1)
|
||||
<< "invalid alignment; expected maximum alignment is "
|
||||
<< max_alignment << ", actual alignment is " << alignment;
|
||||
}
|
||||
unsigned offset_length;
|
||||
offset = decoder->read_u32v<checked>(pc + 1 + alignment_length,
|
||||
|
@ -35,18 +35,18 @@ namespace wasm {
|
||||
#define TRACE(...)
|
||||
#endif
|
||||
|
||||
#define CHECK_PROTOTYPE_OPCODE(flag) \
|
||||
if (module_ != nullptr && module_->is_asm_js()) { \
|
||||
error("Opcode not supported for asmjs modules"); \
|
||||
} \
|
||||
if (!FLAG_experimental_wasm_##flag) { \
|
||||
error("Invalid opcode (enable with --experimental-wasm-" #flag ")"); \
|
||||
break; \
|
||||
#define CHECK_PROTOTYPE_OPCODE(flag) \
|
||||
if (module_ != nullptr && module_->is_asm_js()) { \
|
||||
error() << "Opcode not supported for asmjs modules"; \
|
||||
} \
|
||||
if (!FLAG_experimental_wasm_##flag) { \
|
||||
error() << "Invalid opcode (enable with --experimental-wasm-" #flag ")"; \
|
||||
break; \
|
||||
}
|
||||
|
||||
#define PROTOTYPE_NOT_FUNCTIONAL(opcode) \
|
||||
errorf(pc_, "Prototype still not functional: %s", \
|
||||
WasmOpcodes::OpcodeName(opcode));
|
||||
#define PROTOTYPE_NOT_FUNCTIONAL(opcode) \
|
||||
error() << "Prototype still not functional: " \
|
||||
<< WasmOpcodes::OpcodeName(opcode);
|
||||
|
||||
// An SsaEnv environment carries the current local variable renaming
|
||||
// as well as the current effect and control dependency in the TF graph.
|
||||
@ -194,7 +194,7 @@ class WasmDecoder : public Decoder {
|
||||
if (decoder->failed()) return false;
|
||||
|
||||
if ((count + type_list->size()) > kV8MaxWasmFunctionLocals) {
|
||||
decoder->error(decoder->pc() - 1, "local count too large");
|
||||
decoder->error(decoder->pc() - 1) << "local count too large";
|
||||
return false;
|
||||
}
|
||||
byte code = decoder->consume_u8("local type");
|
||||
@ -218,7 +218,7 @@ class WasmDecoder : public Decoder {
|
||||
type = kWasmS128;
|
||||
break;
|
||||
default:
|
||||
decoder->error(decoder->pc() - 1, "invalid local type");
|
||||
decoder->error(decoder->pc() - 1) << "invalid local type";
|
||||
return false;
|
||||
}
|
||||
type_list->insert(type_list->end(), count, type);
|
||||
@ -279,7 +279,7 @@ class WasmDecoder : public Decoder {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
errorf(pc + 1, "invalid local index: %u", operand.index);
|
||||
error(pc + 1) << "invalid local index: " << operand.index;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -289,7 +289,7 @@ class WasmDecoder : public Decoder {
|
||||
operand.type = operand.global->type;
|
||||
return true;
|
||||
}
|
||||
errorf(pc + 1, "invalid global index: %u", operand.index);
|
||||
error(pc + 1) << "invalid global index: " << operand.index;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -305,7 +305,7 @@ class WasmDecoder : public Decoder {
|
||||
if (Complete(pc, operand)) {
|
||||
return true;
|
||||
}
|
||||
errorf(pc + 1, "invalid function index: %u", operand.index);
|
||||
error(pc + 1) << "invalid function index: " << operand.index;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -319,13 +319,13 @@ class WasmDecoder : public Decoder {
|
||||
|
||||
inline bool Validate(const byte* pc, CallIndirectOperand<true>& operand) {
|
||||
if (module_ == nullptr || module_->function_tables.empty()) {
|
||||
error("function table has to exist to execute call_indirect");
|
||||
error() << "function table has to exist to execute call_indirect";
|
||||
return false;
|
||||
}
|
||||
if (Complete(pc, operand)) {
|
||||
return true;
|
||||
}
|
||||
errorf(pc + 1, "invalid signature index: #%u", operand.index);
|
||||
error(pc + 1) << "invalid signature index: #" << operand.index;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -335,15 +335,15 @@ class WasmDecoder : public Decoder {
|
||||
operand.target = &control[control.size() - operand.depth - 1];
|
||||
return true;
|
||||
}
|
||||
errorf(pc + 1, "invalid break depth: %u", operand.depth);
|
||||
error(pc + 1) << "invalid break depth: " << operand.depth;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Validate(const byte* pc, BranchTableOperand<true>& operand,
|
||||
size_t block_depth) {
|
||||
if (operand.table_count >= kV8MaxWasmFunctionSize) {
|
||||
errorf(pc + 1, "invalid table count (> max function size): %u",
|
||||
operand.table_count);
|
||||
error(pc + 1) << "invalid table count (> max function size): "
|
||||
<< operand.table_count;
|
||||
return false;
|
||||
}
|
||||
return checkAvailable(operand.table_count);
|
||||
@ -372,7 +372,7 @@ class WasmDecoder : public Decoder {
|
||||
break;
|
||||
}
|
||||
if (operand.lane < 0 || operand.lane >= num_lanes) {
|
||||
error(pc_ + 2, "invalid lane index");
|
||||
error(pc_ + 2) << "invalid lane index";
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
@ -403,7 +403,7 @@ class WasmDecoder : public Decoder {
|
||||
break;
|
||||
}
|
||||
if (operand.shift < 0 || operand.shift >= max_shift) {
|
||||
error(pc_ + 2, "invalid shift amount");
|
||||
error(pc_ + 2) << "invalid shift amount";
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
@ -416,7 +416,7 @@ class WasmDecoder : public Decoder {
|
||||
max_lane = std::max(max_lane, operand.shuffle[i]);
|
||||
// Shuffle indices must be in [0..31] for a 16 lane shuffle.
|
||||
if (max_lane > 2 * kSimd128Size) {
|
||||
error(pc_ + 2, "invalid shuffle mask");
|
||||
error(pc_ + 2) << "invalid shuffle mask";
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
@ -515,7 +515,7 @@ class WasmDecoder : public Decoder {
|
||||
case kExprS8x16Shuffle:
|
||||
return 2 + kSimd128Size;
|
||||
default:
|
||||
decoder->error(pc, "invalid SIMD opcode");
|
||||
decoder->error(pc) << "invalid SIMD opcode";
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
@ -621,7 +621,7 @@ class WasmFullDecoder : public WasmDecoder {
|
||||
control_.clear();
|
||||
|
||||
if (end_ < pc_) {
|
||||
error("function body end < start");
|
||||
error() << "function body end < start";
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -637,15 +637,15 @@ class WasmFullDecoder : public WasmDecoder {
|
||||
// Generate a better error message whether the unterminated control
|
||||
// structure is the function body block or an innner structure.
|
||||
if (control_.size() > 1) {
|
||||
error(control_.back().pc, "unterminated control structure");
|
||||
error(control_.back().pc) << "unterminated control structure";
|
||||
} else {
|
||||
error("function body must end with \"end\" opcode");
|
||||
error() << "function body must end with \"end\" opcode";
|
||||
}
|
||||
return TraceFailed();
|
||||
}
|
||||
|
||||
if (!last_end_found_) {
|
||||
error("function body must end with \"end\" opcode");
|
||||
error() << "function body must end with \"end\" opcode";
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -747,7 +747,7 @@ class WasmFullDecoder : public WasmDecoder {
|
||||
|
||||
bool CheckHasMemory() {
|
||||
if (!module_->has_memory) {
|
||||
error(pc_ - 1, "memory instruction with no memory");
|
||||
error(pc_ - 1) << "memory instruction with no memory";
|
||||
}
|
||||
return module_->has_memory;
|
||||
}
|
||||
@ -843,18 +843,18 @@ class WasmFullDecoder : public WasmDecoder {
|
||||
len = 1 + operand.length;
|
||||
|
||||
if (control_.empty()) {
|
||||
error("catch does not match any try");
|
||||
error() << "catch does not match any try";
|
||||
break;
|
||||
}
|
||||
|
||||
Control* c = &control_.back();
|
||||
if (!c->is_try()) {
|
||||
error("catch does not match any try");
|
||||
error() << "catch does not match any try";
|
||||
break;
|
||||
}
|
||||
|
||||
if (c->try_info->catch_env == nullptr) {
|
||||
error(pc_, "catch already present for try with catch");
|
||||
error() << "catch already present for try with catch";
|
||||
break;
|
||||
}
|
||||
|
||||
@ -915,16 +915,16 @@ class WasmFullDecoder : public WasmDecoder {
|
||||
}
|
||||
case kExprElse: {
|
||||
if (control_.empty()) {
|
||||
error("else does not match any if");
|
||||
error() << "else does not match any if";
|
||||
break;
|
||||
}
|
||||
Control* c = &control_.back();
|
||||
if (!c->is_if()) {
|
||||
error(pc_, "else does not match an if");
|
||||
error() << "else does not match an if";
|
||||
break;
|
||||
}
|
||||
if (c->false_env == nullptr) {
|
||||
error(pc_, "else already present for if");
|
||||
error() << "else already present for if";
|
||||
break;
|
||||
}
|
||||
FallThruTo(c);
|
||||
@ -936,7 +936,7 @@ class WasmFullDecoder : public WasmDecoder {
|
||||
}
|
||||
case kExprEnd: {
|
||||
if (control_.empty()) {
|
||||
error("end does not match any if, try, or block");
|
||||
error() << "end does not match any if, try, or block";
|
||||
return;
|
||||
}
|
||||
const char* name = "block:end";
|
||||
@ -954,11 +954,11 @@ class WasmFullDecoder : public WasmDecoder {
|
||||
// End the true branch of a one-armed if.
|
||||
Goto(c->false_env, c->end_env);
|
||||
if (!c->unreachable && stack_.size() != c->stack_depth) {
|
||||
error("end of if expected empty stack");
|
||||
error() << "end of if expected empty stack";
|
||||
stack_.resize(c->stack_depth);
|
||||
}
|
||||
if (c->merge.arity > 0) {
|
||||
error("non-void one-armed if");
|
||||
error() << "non-void one-armed if";
|
||||
}
|
||||
name = "if:merge";
|
||||
} else {
|
||||
@ -970,7 +970,7 @@ class WasmFullDecoder : public WasmDecoder {
|
||||
|
||||
// validate that catch was seen.
|
||||
if (c->try_info->catch_env != nullptr) {
|
||||
error(pc_, "missing catch in try");
|
||||
error(pc_) << "missing catch in try";
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -981,7 +981,7 @@ class WasmFullDecoder : public WasmDecoder {
|
||||
if (control_.size() == 1) {
|
||||
// If at the last (implicit) control, check we are at end.
|
||||
if (pc_ + 1 != end_) {
|
||||
error(pc_ + 1, "trailing code after function end");
|
||||
error(pc_ + 1) << "trailing code after function end";
|
||||
break;
|
||||
}
|
||||
last_end_found_ = true;
|
||||
@ -1058,7 +1058,7 @@ class WasmFullDecoder : public WasmDecoder {
|
||||
const byte* pos = iterator.pc();
|
||||
uint32_t target = iterator.next();
|
||||
if (target >= control_.size()) {
|
||||
error(pos, "improper branch in br_table");
|
||||
error(pos) << "improper branch in br_table";
|
||||
break;
|
||||
}
|
||||
ssa_env_ = Split(copy);
|
||||
@ -1074,18 +1074,18 @@ class WasmFullDecoder : public WasmDecoder {
|
||||
if (i == 0) {
|
||||
merge = current;
|
||||
} else if (merge->arity != current->arity) {
|
||||
errorf(pos,
|
||||
"inconsistent arity in br_table target %d"
|
||||
" (previous was %u, this one %u)",
|
||||
i, merge->arity, current->arity);
|
||||
error(pos) << "inconsistent arity in br_table target " << i
|
||||
<< " (previous was " << merge->arity
|
||||
<< ", this one " << current->arity << ")";
|
||||
} else if (control_.back().unreachable) {
|
||||
for (uint32_t j = 0; ok() && j < merge->arity; ++j) {
|
||||
if ((*merge)[j].type != (*current)[j].type) {
|
||||
errorf(pos,
|
||||
"type error in br_table target %d operand %d"
|
||||
" (previous expected %s, this one %s)",
|
||||
i, j, WasmOpcodes::TypeName((*merge)[j].type),
|
||||
WasmOpcodes::TypeName((*current)[j].type));
|
||||
error(pos)
|
||||
<< "type error in br_table target " << i
|
||||
<< " operand " << j << " (previous expected "
|
||||
<< WasmOpcodes::TypeName((*merge)[j].type)
|
||||
<< ", this one "
|
||||
<< WasmOpcodes::TypeName((*current)[j].type) << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1096,7 +1096,7 @@ class WasmFullDecoder : public WasmDecoder {
|
||||
const byte* pos = iterator.pc();
|
||||
uint32_t target = iterator.next();
|
||||
if (target >= control_.size()) {
|
||||
error(pos, "improper branch in br_table");
|
||||
error(pos) << "improper branch in br_table";
|
||||
break;
|
||||
}
|
||||
BreakTo(target);
|
||||
@ -1191,8 +1191,8 @@ class WasmFullDecoder : public WasmDecoder {
|
||||
Value val = Pop(0, operand.type);
|
||||
BUILD(SetGlobal, operand.index, val.node);
|
||||
} else {
|
||||
errorf(pc_, "immutable global #%u cannot be assigned",
|
||||
operand.index);
|
||||
error() << "immutable global #" << operand.index
|
||||
<< " cannot be assigned";
|
||||
}
|
||||
}
|
||||
len = 1 + operand.length;
|
||||
@ -1275,7 +1275,7 @@ class WasmFullDecoder : public WasmDecoder {
|
||||
Value val = Pop(0, kWasmI32);
|
||||
Push(kWasmI32, BUILD(GrowMemory, val.node));
|
||||
} else {
|
||||
error("grow_memory is not supported for asmjs modules");
|
||||
error() << "grow_memory is not supported for asmjs modules";
|
||||
}
|
||||
len = 1 + operand.length;
|
||||
break;
|
||||
@ -1323,7 +1323,7 @@ class WasmFullDecoder : public WasmDecoder {
|
||||
}
|
||||
case kAtomicPrefix: {
|
||||
if (module_ == nullptr || !module_->is_asm_js()) {
|
||||
error("Atomics are allowed only in AsmJs modules");
|
||||
error() << "Atomics are allowed only in AsmJs modules";
|
||||
break;
|
||||
}
|
||||
CHECK_PROTOTYPE_OPCODE(threads);
|
||||
@ -1344,7 +1344,7 @@ class WasmFullDecoder : public WasmDecoder {
|
||||
BuildSimpleOperator(opcode, sig);
|
||||
}
|
||||
} else {
|
||||
error("Invalid opcode");
|
||||
error() << "Invalid opcode";
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1418,7 +1418,7 @@ class WasmFullDecoder : public WasmDecoder {
|
||||
#endif
|
||||
pc_ += len;
|
||||
} // end decode loop
|
||||
if (pc_ > end_ && ok()) error("Beyond end of code");
|
||||
if (pc_ > end_ && ok()) error() << "Beyond end of code";
|
||||
}
|
||||
|
||||
void FinishFunction() {
|
||||
@ -1638,7 +1638,7 @@ class WasmFullDecoder : public WasmDecoder {
|
||||
TFNode* node = BUILD(SimdOp, opcode, inputs.data());
|
||||
Push(GetReturnType(sig), node);
|
||||
} else {
|
||||
error("invalid simd opcode");
|
||||
error() << "invalid simd opcode";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1696,9 +1696,10 @@ class WasmFullDecoder : public WasmDecoder {
|
||||
Value Pop(int index, ValueType expected) {
|
||||
Value val = Pop();
|
||||
if (val.type != expected && val.type != kWasmVar && expected != kWasmVar) {
|
||||
errorf(val.pc, "%s[%d] expected type %s, found %s of type %s",
|
||||
SafeOpcodeNameAt(pc_), index, WasmOpcodes::TypeName(expected),
|
||||
SafeOpcodeNameAt(val.pc), WasmOpcodes::TypeName(val.type));
|
||||
error(val.pc) << SafeOpcodeNameAt(pc_) << "[" << index
|
||||
<< "] expected type " << WasmOpcodes::TypeName(expected)
|
||||
<< ", found " << SafeOpcodeNameAt(val.pc) << " of type "
|
||||
<< WasmOpcodes::TypeName(val.type);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
@ -1709,7 +1710,7 @@ class WasmFullDecoder : public WasmDecoder {
|
||||
// Popping past the current control start in reachable code.
|
||||
Value val = {pc_, nullptr, kWasmVar};
|
||||
if (!control_.back().unreachable) {
|
||||
errorf(pc_, "%s found empty stack", SafeOpcodeNameAt(pc_));
|
||||
error(pc_) << SafeOpcodeNameAt(pc_) << " found empty stack";
|
||||
}
|
||||
return val;
|
||||
}
|
||||
@ -1729,11 +1730,9 @@ class WasmFullDecoder : public WasmDecoder {
|
||||
// Merge the value(s) into the end of the block.
|
||||
size_t expected = control_.back().stack_depth + c->merge.arity;
|
||||
if (stack_.size() < expected && !control_.back().unreachable) {
|
||||
errorf(
|
||||
pc_,
|
||||
"expected at least %u values on the stack for br to @%d, found %d",
|
||||
c->merge.arity, startrel(c->pc),
|
||||
static_cast<int>(stack_.size() - c->stack_depth));
|
||||
error() << "expected at least " << c->merge.arity
|
||||
<< " values on the stack for br to @" << startrel(c->pc)
|
||||
<< ", found " << stack_.size() - c->stack_depth;
|
||||
return;
|
||||
}
|
||||
MergeValuesInto(c);
|
||||
@ -1750,8 +1749,9 @@ class WasmFullDecoder : public WasmDecoder {
|
||||
c->unreachable = false;
|
||||
return;
|
||||
}
|
||||
errorf(pc_, "expected %u elements on the stack for fallthru to @%d",
|
||||
c->merge.arity, startrel(c->pc));
|
||||
error() << "expected " << c->merge.arity
|
||||
<< " elements on the stack for fallthru to @",
|
||||
startrel(c->pc);
|
||||
}
|
||||
|
||||
inline Value& GetMergeValueFromStack(Control* c, size_t i) {
|
||||
@ -1764,8 +1764,8 @@ class WasmFullDecoder : public WasmDecoder {
|
||||
int arity = static_cast<int>(c->merge.arity);
|
||||
if (c->stack_depth + arity < stack_.size() ||
|
||||
(c->stack_depth + arity != stack_.size() && !c->unreachable)) {
|
||||
errorf(pc_, "expected %d elements on the stack for fallthru to @%d",
|
||||
arity, startrel(c->pc));
|
||||
error() << "expected " << arity
|
||||
<< " elements on the stack for fallthru to @" << startrel(c->pc);
|
||||
return;
|
||||
}
|
||||
// Typecheck the values left on the stack.
|
||||
@ -1775,9 +1775,9 @@ class WasmFullDecoder : public WasmDecoder {
|
||||
Value& val = GetMergeValueFromStack(c, i);
|
||||
Value& old = c->merge[i];
|
||||
if (val.type != old.type) {
|
||||
errorf(pc_, "type error in merge[%zu] (expected %s, got %s)", i,
|
||||
WasmOpcodes::TypeName(old.type),
|
||||
WasmOpcodes::TypeName(val.type));
|
||||
error() << "type error in merge[" << i << "] (expected "
|
||||
<< WasmOpcodes::TypeName(old.type) << ", got "
|
||||
<< WasmOpcodes::TypeName(val.type) << ")";
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1795,9 +1795,9 @@ class WasmFullDecoder : public WasmDecoder {
|
||||
Value& val = GetMergeValueFromStack(c, i);
|
||||
Value& old = c->merge[i];
|
||||
if (val.type != old.type && val.type != kWasmVar) {
|
||||
errorf(pc_, "type error in merge[%zu] (expected %s, got %s)", i,
|
||||
WasmOpcodes::TypeName(old.type),
|
||||
WasmOpcodes::TypeName(val.type));
|
||||
error() << "type error in merge[" << i << "] (expected "
|
||||
<< WasmOpcodes::TypeName(old.type) << ", got "
|
||||
<< WasmOpcodes::TypeName(val.type) << ")";
|
||||
return;
|
||||
}
|
||||
if (builder_ && reachable) {
|
||||
|
@ -112,7 +112,7 @@ WireBytesRef consume_string(Decoder& decoder, bool validate_utf8,
|
||||
decoder.consume_bytes(length, name);
|
||||
if (decoder.ok() && validate_utf8 &&
|
||||
!unibrow::Utf8::ValidateEncoding(string_start, length)) {
|
||||
decoder.errorf(string_start, "%s: no valid UTF-8 string", name);
|
||||
decoder.error(string_start) << name << ": no valid UTF-8 string";
|
||||
}
|
||||
}
|
||||
return {offset, decoder.failed() ? 0 : length};
|
||||
@ -161,11 +161,10 @@ class WasmSectionIterator {
|
||||
}
|
||||
if (decoder_.pc() != section_end_) {
|
||||
const char* msg = decoder_.pc() < section_end_ ? "shorter" : "longer";
|
||||
decoder_.errorf(decoder_.pc(),
|
||||
"section was %s than expected size "
|
||||
"(%u bytes expected, %zu decoded)",
|
||||
msg, section_length(),
|
||||
static_cast<size_t>(decoder_.pc() - section_start_));
|
||||
decoder_.error(decoder_.pc())
|
||||
<< "section was " << msg << " than expected size ("
|
||||
<< section_length() << " bytes expected, "
|
||||
<< decoder_.pc() - section_start_ << " decoded)";
|
||||
}
|
||||
next();
|
||||
}
|
||||
@ -225,8 +224,8 @@ class WasmSectionIterator {
|
||||
section_code = kExceptionSectionCode;
|
||||
}
|
||||
} else if (!IsValidSectionCode(section_code)) {
|
||||
decoder_.errorf(decoder_.pc(), "unknown section code #0x%02x",
|
||||
section_code);
|
||||
decoder_.error() << "unknown section code "
|
||||
<< AsHex(section_code, 2, true);
|
||||
section_code = kUnknownSectionCode;
|
||||
}
|
||||
section_code_ = decoder_.failed() ? kUnknownSectionCode
|
||||
@ -249,7 +248,7 @@ class ModuleDecoder : public Decoder {
|
||||
: Decoder(module_start, module_end),
|
||||
origin_(FLAG_assume_asmjs_origin ? kAsmJsOrigin : origin) {
|
||||
if (end_ < start_) {
|
||||
error(start_, "end is less than start");
|
||||
error(start_) << "end is less than start";
|
||||
end_ = start_;
|
||||
}
|
||||
}
|
||||
@ -301,22 +300,17 @@ class ModuleDecoder : public Decoder {
|
||||
|
||||
const byte* pos = pc_;
|
||||
uint32_t magic_word = consume_u32("wasm magic");
|
||||
#define BYTES(x) (x & 0xff), (x >> 8) & 0xff, (x >> 16) & 0xff, (x >> 24) & 0xff
|
||||
if (magic_word != kWasmMagic) {
|
||||
errorf(pos,
|
||||
"expected magic word %02x %02x %02x %02x, "
|
||||
"found %02x %02x %02x %02x",
|
||||
BYTES(kWasmMagic), BYTES(magic_word));
|
||||
error(pos) << "expected magic word " << AsHexBytes(kWasmMagic, 4)
|
||||
<< ", found " << AsHexBytes(magic_word, 4);
|
||||
}
|
||||
|
||||
pos = pc_;
|
||||
{
|
||||
uint32_t magic_version = consume_u32("wasm version");
|
||||
if (magic_version != kWasmVersion) {
|
||||
errorf(pos,
|
||||
"expected version %02x %02x %02x %02x, "
|
||||
"found %02x %02x %02x %02x",
|
||||
BYTES(kWasmVersion), BYTES(magic_version));
|
||||
error(pos) << "expected version " << AsHexBytes(kWasmVersion, 4)
|
||||
<< ", found " << AsHexBytes(magic_version, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -328,7 +322,7 @@ class ModuleDecoder : public Decoder {
|
||||
|
||||
// Check if the section is out-of-order.
|
||||
if (section_code < next_section_) {
|
||||
errorf(pc(), "unexpected section: %s", SectionName(section_code));
|
||||
error() << "unexpected section: " << SectionName(section_code);
|
||||
return;
|
||||
}
|
||||
if (section_code != kUnknownSectionCode) {
|
||||
@ -379,16 +373,15 @@ class ModuleDecoder : public Decoder {
|
||||
DecodeExceptionSection();
|
||||
break;
|
||||
default:
|
||||
errorf(pc(), "unexpected section: %s", SectionName(section_code));
|
||||
error() << "unexpected section: " << SectionName(section_code);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pc() != bytes.end()) {
|
||||
const char* msg = pc() < bytes.end() ? "shorter" : "longer";
|
||||
errorf(pc(),
|
||||
"section was %s than expected size "
|
||||
"(%zu bytes expected, %zu decoded)",
|
||||
msg, bytes.size(), static_cast<size_t>(pc() - bytes.begin()));
|
||||
error() << "section was " << msg << " than expected size ("
|
||||
<< bytes.size() << " bytes expected, " << pc() - bytes.begin()
|
||||
<< " decoded)";
|
||||
}
|
||||
}
|
||||
|
||||
@ -472,12 +465,12 @@ class ModuleDecoder : public Decoder {
|
||||
global->type = consume_value_type();
|
||||
global->mutability = consume_mutability();
|
||||
if (global->mutability) {
|
||||
error("mutable globals cannot be imported");
|
||||
error() << "mutable globals cannot be imported";
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
errorf(pos, "unknown import kind 0x%02x", import->kind);
|
||||
error(pos) << "unknown import kind " << AsHex(import->kind, 2, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -581,7 +574,7 @@ class ModuleDecoder : public Decoder {
|
||||
// TODO(titzer): This should become more regular
|
||||
// once we support multiple memories.
|
||||
if (!module_->has_memory || index != 0) {
|
||||
error("invalid memory index != 0");
|
||||
error() << "invalid memory index != 0";
|
||||
}
|
||||
module_->mem_export = true;
|
||||
break;
|
||||
@ -591,14 +584,14 @@ class ModuleDecoder : public Decoder {
|
||||
exp->index = consume_global_index(module_.get(), &global);
|
||||
if (global) {
|
||||
if (global->mutability) {
|
||||
error("mutable globals cannot be exported");
|
||||
error() << "mutable globals cannot be exported";
|
||||
}
|
||||
global->exported = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
errorf(pos, "invalid export kind 0x%02x", exp->kind);
|
||||
error(pos) << "invalid export kind " << AsHex(exp->kind, 2, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -623,9 +616,12 @@ class ModuleDecoder : public Decoder {
|
||||
DCHECK(!cmp_less(*it, *last)); // Vector must be sorted.
|
||||
if (!cmp_less(*last, *it)) {
|
||||
const byte* pc = start() + GetBufferRelativeOffset(it->name.offset());
|
||||
errorf(pc, "Duplicate export name '%.*s' for %s %d and %s %d",
|
||||
it->name.length(), pc, ExternalKindName(last->kind),
|
||||
last->index, ExternalKindName(it->kind), it->index);
|
||||
std::string name(reinterpret_cast<const char*>(pc),
|
||||
it->name.length());
|
||||
error(pc) << "Duplicate export name '" << name << "' for "
|
||||
<< ExternalKindName(last->kind) << " " << last->index
|
||||
<< " and " << ExternalKindName(it->kind) << " "
|
||||
<< it->index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -638,7 +634,8 @@ class ModuleDecoder : public Decoder {
|
||||
module_->start_function_index = consume_func_index(module_.get(), &func);
|
||||
if (func &&
|
||||
(func->sig->parameter_count() > 0 || func->sig->return_count() > 0)) {
|
||||
error(pos, "invalid start function: non-zero parameter or return count");
|
||||
error(pos)
|
||||
<< "invalid start function: non-zero parameter or return count";
|
||||
}
|
||||
}
|
||||
|
||||
@ -649,11 +646,11 @@ class ModuleDecoder : public Decoder {
|
||||
const byte* pos = pc();
|
||||
uint32_t table_index = consume_u32v("table index");
|
||||
if (table_index != 0) {
|
||||
errorf(pos, "illegal table index %u != 0", table_index);
|
||||
error(pos) << "illegal table index " << table_index << " != 0";
|
||||
}
|
||||
WasmIndirectFunctionTable* table = nullptr;
|
||||
if (table_index >= module_->function_tables.size()) {
|
||||
errorf(pos, "out of bounds table index %u", table_index);
|
||||
error(pos) << "out of bounds table index " << table_index;
|
||||
break;
|
||||
}
|
||||
table = &module_->function_tables[table_index];
|
||||
@ -679,8 +676,8 @@ class ModuleDecoder : public Decoder {
|
||||
const byte* pos = pc_;
|
||||
uint32_t functions_count = consume_u32v("functions count");
|
||||
if (functions_count != module_->num_declared_functions) {
|
||||
errorf(pos, "function body count %u mismatch (%u expected)",
|
||||
functions_count, module_->num_declared_functions);
|
||||
error(pos) << "function body count " << functions_count << " mismatch ("
|
||||
<< module_->num_declared_functions << " expected)";
|
||||
}
|
||||
for (uint32_t i = 0; i < functions_count; ++i) {
|
||||
uint32_t size = consume_u32v("body size");
|
||||
@ -706,7 +703,7 @@ class ModuleDecoder : public Decoder {
|
||||
module_->data_segments.reserve(data_segments_count);
|
||||
for (uint32_t i = 0; ok() && i < data_segments_count; ++i) {
|
||||
if (!module_->has_memory) {
|
||||
error("cannot load data without memory");
|
||||
error() << "cannot load data without memory";
|
||||
break;
|
||||
}
|
||||
TRACE("DecodeDataSegment[%d] module+%d\n", i,
|
||||
@ -728,7 +725,7 @@ class ModuleDecoder : public Decoder {
|
||||
// Be lenient with their order.
|
||||
while (inner.ok() && inner.more()) {
|
||||
uint8_t name_type = inner.consume_u8("name type");
|
||||
if (name_type & 0x80) inner.error("name type if not varuint7");
|
||||
if (name_type & 0x80) inner.error() << "name type if not varuint7";
|
||||
|
||||
uint32_t name_payload_len = inner.consume_u32v("name payload length");
|
||||
if (!inner.checkAvailable(name_payload_len)) break;
|
||||
@ -872,7 +869,7 @@ class ModuleDecoder : public Decoder {
|
||||
|
||||
bool AddTable(WasmModule* module) {
|
||||
if (module->function_tables.size() > 0) {
|
||||
error("At most one table is supported");
|
||||
error() << "At most one table is supported";
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
@ -881,7 +878,7 @@ class ModuleDecoder : public Decoder {
|
||||
|
||||
bool AddMemory(WasmModule* module) {
|
||||
if (module->has_memory) {
|
||||
error("At most one memory is supported");
|
||||
error() << "At most one memory is supported";
|
||||
return false;
|
||||
} else {
|
||||
module->has_memory = true;
|
||||
@ -900,25 +897,22 @@ class ModuleDecoder : public Decoder {
|
||||
case WasmInitExpr::kGlobalIndex: {
|
||||
uint32_t other_index = global->init.val.global_index;
|
||||
if (other_index >= index) {
|
||||
errorf(pos,
|
||||
"invalid global index in init expression, "
|
||||
"index %u, other_index %u",
|
||||
index, other_index);
|
||||
error(pos) << "invalid global index in init expression, index "
|
||||
<< index << ", other_index " << other_index;
|
||||
} else if (module->globals[other_index].type != global->type) {
|
||||
errorf(pos,
|
||||
"type mismatch in global initialization "
|
||||
"(from global #%u), expected %s, got %s",
|
||||
other_index, WasmOpcodes::TypeName(global->type),
|
||||
WasmOpcodes::TypeName(module->globals[other_index].type));
|
||||
error(pos) << "type mismatch in global initialization (from global #"
|
||||
<< other_index << "), expected "
|
||||
<< WasmOpcodes::TypeName(global->type) << ", got "
|
||||
<< WasmOpcodes::TypeName(
|
||||
module->globals[other_index].type);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if (global->type != TypeOf(module, global->init)) {
|
||||
errorf(pos,
|
||||
"type error in global initialization, expected %s, got %s",
|
||||
WasmOpcodes::TypeName(global->type),
|
||||
WasmOpcodes::TypeName(TypeOf(module, global->init)));
|
||||
error(pos) << "type error in global initialization, expected "
|
||||
<< WasmOpcodes::TypeName(global->type) << ", got "
|
||||
<< WasmOpcodes::TypeName(TypeOf(module, global->init));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -942,7 +936,7 @@ class ModuleDecoder : public Decoder {
|
||||
uint32_t limit = static_cast<uint32_t>(end_ - start_);
|
||||
if (!IsWithinLimit(limit, GetBufferRelativeOffset(segment->source.offset()),
|
||||
segment->source.length())) {
|
||||
error(start, "segment out of bounds of the section");
|
||||
error(start) << "segment out of bounds of the section";
|
||||
}
|
||||
|
||||
consume_bytes(segment->source.length(), "segment data");
|
||||
@ -1007,8 +1001,8 @@ class ModuleDecoder : public Decoder {
|
||||
const byte* pos = pc_;
|
||||
uint32_t sig_index = consume_u32v("signature index");
|
||||
if (sig_index >= module->signatures.size()) {
|
||||
errorf(pos, "signature index %u out of bounds (%d signatures)", sig_index,
|
||||
static_cast<int>(module->signatures.size()));
|
||||
error(pos) << "signature index " << sig_index << " out of bounds ("
|
||||
<< module->signatures.size() << " signatures)";
|
||||
*sig = nullptr;
|
||||
return 0;
|
||||
}
|
||||
@ -1020,7 +1014,8 @@ class ModuleDecoder : public Decoder {
|
||||
const byte* p = pc_;
|
||||
uint32_t count = consume_u32v(name);
|
||||
if (count > maximum) {
|
||||
errorf(p, "%s of %u exceeds internal limit of %zu", name, count, maximum);
|
||||
error(p) << name << " of " << count << " exceeds internal limit of "
|
||||
<< maximum;
|
||||
return static_cast<uint32_t>(maximum);
|
||||
}
|
||||
return count;
|
||||
@ -1044,8 +1039,8 @@ class ModuleDecoder : public Decoder {
|
||||
const byte* pos = pc_;
|
||||
uint32_t index = consume_u32v(name);
|
||||
if (index >= vector.size()) {
|
||||
errorf(pos, "%s %u out of bounds (%d entr%s)", name, index,
|
||||
static_cast<int>(vector.size()), vector.size() == 1 ? "y" : "ies");
|
||||
error(pos) << name << " " << index << " out of bounds (" << vector.size()
|
||||
<< " entr" << (vector.size() == 1 ? "y" : "ies") << ")";
|
||||
*ptr = nullptr;
|
||||
return 0;
|
||||
}
|
||||
@ -1062,23 +1057,23 @@ class ModuleDecoder : public Decoder {
|
||||
*initial = consume_u32v("initial size");
|
||||
*has_max = false;
|
||||
if (*initial > max_initial) {
|
||||
errorf(pos,
|
||||
"initial %s size (%u %s) is larger than implementation limit (%u)",
|
||||
name, *initial, units, max_initial);
|
||||
error(pos) << "initial " << name << " size (" << *initial << " " << units
|
||||
<< ") is larger than implementation limit (" << max_initial
|
||||
<< ")";
|
||||
}
|
||||
if (flags & 1) {
|
||||
*has_max = true;
|
||||
pos = pc();
|
||||
*maximum = consume_u32v("maximum size");
|
||||
if (*maximum > max_maximum) {
|
||||
errorf(
|
||||
pos,
|
||||
"maximum %s size (%u %s) is larger than implementation limit (%u)",
|
||||
name, *maximum, units, max_maximum);
|
||||
error(pos) << "maximum " << name << " size (" << *maximum << units
|
||||
<< ") is larger than implementation limit (" << max_maximum
|
||||
<< ")";
|
||||
}
|
||||
if (*maximum < *initial) {
|
||||
errorf(pos, "maximum %s size (%u %s) is less than initial (%u %s)",
|
||||
name, *maximum, units, *initial, units);
|
||||
error(pos) << "maximum " << name << " size (" << *maximum << " "
|
||||
<< units << ") is less than initial (" << *initial << " "
|
||||
<< units << ")";
|
||||
}
|
||||
} else {
|
||||
*has_max = false;
|
||||
@ -1090,7 +1085,8 @@ class ModuleDecoder : public Decoder {
|
||||
const byte* pos = pc();
|
||||
uint8_t value = consume_u8(name);
|
||||
if (value != expected) {
|
||||
errorf(pos, "expected %s 0x%02x, got 0x%02x", name, expected, value);
|
||||
error(pos) << "expected " << name << " " << AsHex(expected, 2, true)
|
||||
<< "<< got " << AsHex(value, 2, true);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -1105,16 +1101,15 @@ class ModuleDecoder : public Decoder {
|
||||
case kExprGetGlobal: {
|
||||
GlobalIndexOperand<true> operand(this, pc() - 1);
|
||||
if (module->globals.size() <= operand.index) {
|
||||
error("global index is out of bounds");
|
||||
error() << "global index is out of bounds";
|
||||
expr.kind = WasmInitExpr::kNone;
|
||||
expr.val.i32_const = 0;
|
||||
break;
|
||||
}
|
||||
WasmGlobal* global = &module->globals[operand.index];
|
||||
if (global->mutability || !global->imported) {
|
||||
error(
|
||||
"only immutable imported globals can be used in initializer "
|
||||
"expressions");
|
||||
error() << "only immutable imported globals can be used in "
|
||||
"initializer expressions";
|
||||
expr.kind = WasmInitExpr::kNone;
|
||||
expr.val.i32_const = 0;
|
||||
break;
|
||||
@ -1153,7 +1148,7 @@ class ModuleDecoder : public Decoder {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
error("invalid opcode in initialization expression");
|
||||
error() << "invalid opcode in initialization expression";
|
||||
expr.kind = WasmInitExpr::kNone;
|
||||
expr.val.i32_const = 0;
|
||||
}
|
||||
@ -1163,9 +1158,9 @@ class ModuleDecoder : public Decoder {
|
||||
expr.kind = WasmInitExpr::kNone;
|
||||
}
|
||||
if (expected != kWasmStmt && TypeOf(module, expr) != kWasmI32) {
|
||||
errorf(pos, "type error in init expression, expected %s, got %s",
|
||||
WasmOpcodes::TypeName(expected),
|
||||
WasmOpcodes::TypeName(TypeOf(module, expr)));
|
||||
error(pos) << "type error in init expression, expected "
|
||||
<< WasmOpcodes::TypeName(expected) << ", got "
|
||||
<< WasmOpcodes::TypeName(TypeOf(module, expr));
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
@ -1173,7 +1168,7 @@ class ModuleDecoder : public Decoder {
|
||||
// Read a mutability flag
|
||||
bool consume_mutability() {
|
||||
byte val = consume_u8("mutability");
|
||||
if (val > 1) error(pc_ - 1, "invalid mutability");
|
||||
if (val > 1) error(pc_ - 1) << "invalid mutability";
|
||||
return val != 0;
|
||||
}
|
||||
|
||||
@ -1199,7 +1194,7 @@ class ModuleDecoder : public Decoder {
|
||||
break;
|
||||
}
|
||||
}
|
||||
error(pc_ - 1, "invalid local type");
|
||||
error(pc_ - 1) << "invalid local type";
|
||||
return kWasmStmt;
|
||||
}
|
||||
}
|
||||
@ -1378,7 +1373,7 @@ AsmJsOffsetsResult DecodeAsmJsOffsets(const byte* tables_start,
|
||||
continue;
|
||||
}
|
||||
if (!decoder.checkAvailable(size)) {
|
||||
decoder.error("illegal asm function offset table size");
|
||||
decoder.error() << "illegal asm function offset table size";
|
||||
}
|
||||
const byte* table_end = decoder.pc() + size;
|
||||
uint32_t locals_size = decoder.consume_u32v("locals size");
|
||||
@ -1401,11 +1396,11 @@ AsmJsOffsetsResult DecodeAsmJsOffsets(const byte* tables_start,
|
||||
{last_byte_offset, call_position, to_number_position});
|
||||
}
|
||||
if (decoder.pc() != table_end) {
|
||||
decoder.error("broken asm offset table");
|
||||
decoder.error() << "broken asm offset table";
|
||||
}
|
||||
table.push_back(std::move(func_asm_offsets));
|
||||
}
|
||||
if (decoder.more()) decoder.error("unexpected additional bytes");
|
||||
if (decoder.more()) decoder.error() << "unexpected additional bytes";
|
||||
|
||||
return decoder.toResult(std::move(table));
|
||||
}
|
||||
|
@ -237,35 +237,31 @@ StreamingDecoder::DecodeVarInt32::Next(StreamingDecoder* streaming) {
|
||||
return nullptr;
|
||||
}
|
||||
if (value() > max_value_) {
|
||||
streaming->decoder()->errorf(buffer(), "size > maximum function size: %zu",
|
||||
value());
|
||||
streaming->decoder()->error(buffer())
|
||||
<< "size > maximum function size: " << value();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return NextWithValue(streaming);
|
||||
}
|
||||
|
||||
#define BYTES(x) (x & 0xff), (x >> 8) & 0xff, (x >> 16) & 0xff, (x >> 24) & 0xff
|
||||
// Decode the module header. The error state of the decoder stores the result.
|
||||
void StreamingDecoder::DecodeModuleHeader::CheckHeader(Decoder* decoder) {
|
||||
// TODO(ahaas): Share code with the module-decoder.
|
||||
decoder->Reset(buffer(), buffer() + size());
|
||||
uint32_t magic_word = decoder->consume_u32("wasm magic");
|
||||
if (magic_word != kWasmMagic) {
|
||||
decoder->errorf(buffer(),
|
||||
"expected magic word %02x %02x %02x %02x, "
|
||||
"found %02x %02x %02x %02x",
|
||||
BYTES(kWasmMagic), BYTES(magic_word));
|
||||
decoder->error(buffer())
|
||||
<< "expected magic word " << AsHexBytes(kWasmMagic, 4) << ", found "
|
||||
<< AsHexBytes(magic_word, 4);
|
||||
}
|
||||
uint32_t magic_version = decoder->consume_u32("wasm version");
|
||||
if (magic_version != kWasmVersion) {
|
||||
decoder->errorf(buffer(),
|
||||
"expected version %02x %02x %02x %02x, "
|
||||
"found %02x %02x %02x %02x",
|
||||
BYTES(kWasmVersion), BYTES(magic_version));
|
||||
decoder->error(buffer())
|
||||
<< "expected version " << AsHexBytes(kWasmVersion, 4) << ", found "
|
||||
<< AsHexBytes(magic_version, 4);
|
||||
}
|
||||
}
|
||||
#undef BYTES
|
||||
|
||||
std::unique_ptr<StreamingDecoder::DecodingState>
|
||||
StreamingDecoder::DecodeModuleHeader::Next(StreamingDecoder* streaming) {
|
||||
@ -309,7 +305,7 @@ StreamingDecoder::DecodeNumberOfFunctions::NextWithValue(
|
||||
memcpy(section_buffer_->bytes() + section_buffer_->payload_offset(),
|
||||
buffer(), bytes_needed());
|
||||
} else {
|
||||
streaming->decoder()->error("Invalid code section length");
|
||||
streaming->decoder()->error() << "Invalid code section length";
|
||||
return base::make_unique<DecodeSectionID>();
|
||||
}
|
||||
|
||||
@ -330,17 +326,17 @@ StreamingDecoder::DecodeFunctionLength::NextWithValue(
|
||||
if (section_buffer_->length() >= buffer_offset_ + bytes_needed()) {
|
||||
memcpy(section_buffer_->bytes() + buffer_offset_, buffer(), bytes_needed());
|
||||
} else {
|
||||
streaming->decoder()->error("Invalid code section length");
|
||||
streaming->decoder()->error() << "Invalid code section length";
|
||||
return base::make_unique<DecodeSectionID>();
|
||||
}
|
||||
|
||||
// {value} is the length of the function.
|
||||
if (value() == 0) {
|
||||
streaming->decoder()->errorf(buffer(), "Invalid function length (0)");
|
||||
streaming->decoder()->error(buffer()) << "Invalid function length (0)";
|
||||
return nullptr;
|
||||
} else if (buffer_offset() + bytes_needed() + value() >
|
||||
section_buffer()->length()) {
|
||||
streaming->decoder()->errorf(buffer(), "not enough code section bytes");
|
||||
streaming->decoder()->error(buffer()) << "not enough code section bytes";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -360,9 +356,9 @@ StreamingDecoder::DecodeFunctionBody::Next(StreamingDecoder* streaming) {
|
||||
streaming->decoder()->Reset(
|
||||
section_buffer()->bytes(),
|
||||
section_buffer()->bytes() + section_buffer()->length());
|
||||
streaming->decoder()->errorf(
|
||||
section_buffer()->bytes() + buffer_offset() + size(),
|
||||
"not all code section bytes were used");
|
||||
streaming->decoder()->error(section_buffer()->bytes() + buffer_offset() +
|
||||
size())
|
||||
<< "not all code section bytes were used";
|
||||
return nullptr;
|
||||
}
|
||||
return base::make_unique<DecodeSectionID>();
|
||||
|
@ -56,3 +56,20 @@ load("test/mjsunit/wasm/wasm-module-builder.js");
|
||||
() => builder.instantiate(), WebAssembly.CompileError,
|
||||
/Duplicate export name 'foo' for global 0 and function 0/);
|
||||
})();
|
||||
|
||||
(function veryLongExportName() {
|
||||
// Regression test for crbug.com/740023.
|
||||
var export_name = 'abc';
|
||||
while (export_name.length < 8192) {
|
||||
export_name = export_name.concat(export_name);
|
||||
}
|
||||
var builder = new WasmModuleBuilder();
|
||||
var global = builder.addGlobal(kWasmI64, false);
|
||||
global.exportAs(export_name);
|
||||
global.exportAs(export_name);
|
||||
var error_msg =
|
||||
'Duplicate export name \'' + export_name + '\' for global 0 and global 0';
|
||||
assertThrows(
|
||||
() => builder.instantiate(), WebAssembly.CompileError,
|
||||
new RegExp(error_msg));
|
||||
})();
|
||||
|
Loading…
Reference in New Issue
Block a user