Commit ea82e096 authored by Clemens Hammacher's avatar Clemens Hammacher Committed by Commit Bot

[wasm] Limit output length of user-provided strings

In order to limit the overall length of error message, limit the output
of string provided by the user. This is implemented by a helper class
which takes the maximum length as template argument and has simple
accessors for the start address and the length of the truncated string.

This is the compromise CL after
https://chromium-review.googlesource.com/c/566815 and
https://chromium-review.googlesource.com/c/594288.

R=titzer@chromium.org

Bug: chromium:740023, chromium:749041, v8:6634
Change-Id: I7c154eb18b3a6befd5ecabbd2f435b015ad71542
Reviewed-on: https://chromium-review.googlesource.com/600547Reviewed-by: 's avatarBen Titzer <titzer@chromium.org>
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47157}
parent b329b249
......@@ -290,10 +290,9 @@ void ModuleCompiler::CompileSequentially(ModuleBytesEnv* module_env,
MaybeHandle<Code> code = compiler::WasmCompilationUnit::CompileWasmFunction(
thrower, isolate_, module_env, &func);
if (code.is_null()) {
WasmName str = module_env->wire_bytes.GetName(&func);
// TODO(clemensh): Truncate the function name in the output.
thrower->CompileError("Compilation of #%d:%.*s failed.", i, str.length(),
str.start());
TruncatedUserString<> name(module_env->wire_bytes.GetName(&func));
thrower->CompileError("Compilation of #%d:%.*s failed.", i, name.length(),
name.start());
break;
}
results[i] = code.ToHandleChecked();
......@@ -315,9 +314,9 @@ void ModuleCompiler::ValidateSequentially(ModuleBytesEnv* module_env,
isolate_->allocator(), module_env->module_env.module, body,
module->is_wasm(), counters());
if (result.failed()) {
WasmName str = module_env->wire_bytes.GetName(&func);
TruncatedUserString<> name(module_env->wire_bytes.GetName(&func));
thrower->CompileError("Compiling function #%d:%.*s failed: %s @+%u", i,
str.length(), str.start(),
name.length(), name.start(),
result.error_msg().c_str(), result.error_offset());
break;
}
......@@ -1691,8 +1690,9 @@ void InstanceBuilder::ProcessExports(
v8::Maybe<bool> status = JSReceiver::DefineOwnProperty(
isolate_, export_to, name, &desc, Object::THROW_ON_ERROR);
if (!status.IsJust()) {
thrower_->LinkError("export of %.*s failed.", name->length(),
name->ToCString().get());
TruncatedUserString<> trunc_name(name->GetCharVector<uint8_t>());
thrower_->LinkError("export of %.*s failed.", trunc_name.length(),
trunc_name.start());
return;
}
}
......
......@@ -640,8 +640,9 @@ 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());
TruncatedUserString<> name(pc, it->name.length());
errorf(pc, "Duplicate export name '%.*s' for %s %d and %s %d",
it->name.length(), pc, ExternalKindName(last->kind),
name.length(), name.start(), ExternalKindName(last->kind),
last->index, ExternalKindName(it->kind), it->index);
break;
}
......
......@@ -548,6 +548,42 @@ class LazyCompilationOrchestrator {
const char* ExternalKindName(WasmExternalKind);
// TruncatedUserString makes it easy to output names up to a certain length, and
// output a truncation followed by '...' if they exceed a limit.
// Use like this:
// TruncatedUserString<> name (pc, len);
// printf("... %.*s ...", name.length(), name.start())
template <int kMaxLen = 50>
class TruncatedUserString {
static_assert(kMaxLen >= 4, "minimum length is 4 (length of '...' plus one)");
public:
template <typename T>
explicit TruncatedUserString(Vector<T> name)
: TruncatedUserString(name.start(), name.length()) {}
TruncatedUserString(const byte* start, size_t len)
: TruncatedUserString(reinterpret_cast<const char*>(start), len) {}
TruncatedUserString(const char* start, size_t len)
: start_(start), length_(std::min(kMaxLen, static_cast<int>(len))) {
if (len > static_cast<size_t>(kMaxLen)) {
memcpy(buffer_, start, kMaxLen - 3);
memset(buffer_ + kMaxLen - 3, '.', 3);
start_ = buffer_;
}
}
const char* start() const { return start_; }
int length() const { return length_; }
private:
const char* start_;
int length_;
char buffer_[kMaxLen];
};
namespace testing {
void ValidateInstancesChain(Isolate* isolate,
Handle<WasmModuleObject> module_obj,
......
......@@ -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 \'(abc){10,20}ab?c?\.\.\.\' for global 0 and global 0';
assertThrows(
() => builder.instantiate(), WebAssembly.CompileError,
new RegExp(error_msg));
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment