Commit 7887ae6f authored by Clemens Backes's avatar Clemens Backes Committed by Commit Bot

[asm] Fix use-after-free in ZoneVectors

The AsmParser kept pointers into ZoneVectors, which were accessed even
after those vector might have grown. For regular vectors, this would be
a use-after-free; with ZoneVectors it is technically allowed, since the
old memory stays alive. This will change with
https://crrev.com/c/2302895, which zaps zone memory which is
deallocated. Eventually, we might want to reuse large deallocations in
zone memory, hence this "use after free" needs to be fixed.

This CL fixes the issue by explicitly re-allocating in the zone instead
of using ZoneVectors. This makes sure that the old memory stays alive.
This is kind of a quick-fix, but since asm.js is more or less deprecated
anyway (in favor of Wasm), it's OK if this code does not profit from
future ZoneVector memory re-use optimizations.

Drive-by: Move field initializers to the field declaration.

R=ishell@chromium.org

Bug: v8:10717
Change-Id: I56c1feb49d05080e78a6620273b55b4e18156254
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2304581Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68917}
parent 42b4f15a
......@@ -75,21 +75,8 @@ AsmJsParser::AsmJsParser(Zone* zone, uintptr_t stack_limit,
: zone_(zone),
scanner_(stream),
module_builder_(zone->New<WasmModuleBuilder>(zone)),
return_type_(nullptr),
stack_limit_(stack_limit),
global_var_info_(zone),
local_var_info_(zone),
failed_(false),
failure_location_(kNoSourcePosition),
stdlib_name_(kTokenNone),
foreign_name_(kTokenNone),
heap_name_(kTokenNone),
inside_heap_assignment_(false),
heap_access_type_(nullptr),
block_stack_(zone),
call_coercion_(nullptr),
call_coercion_deferred_(nullptr),
pending_label_(0),
global_imports_(zone) {
module_builder_->SetMinMemorySize(0);
InitializeStdlibTypes();
......@@ -211,24 +198,21 @@ class AsmJsParser::TemporaryVariableScope {
wasm::AsmJsParser::VarInfo* AsmJsParser::GetVarInfo(
AsmJsScanner::token_t token) {
if (AsmJsScanner::IsGlobal(token)) {
size_t old = global_var_info_.size();
size_t index = AsmJsScanner::GlobalIndex(token);
size_t sz = std::max(old, index + 1);
if (sz != old) {
global_var_info_.resize(sz);
}
return &global_var_info_[index];
} else if (AsmJsScanner::IsLocal(token)) {
size_t old = local_var_info_.size();
size_t index = AsmJsScanner::LocalIndex(token);
size_t sz = std::max(old, index + 1);
if (sz != old) {
local_var_info_.resize(sz);
}
return &local_var_info_[index];
}
UNREACHABLE();
const bool is_global = AsmJsScanner::IsGlobal(token);
DCHECK(is_global || AsmJsScanner::IsLocal(token));
Vector<VarInfo>& var_info = is_global ? global_var_info_ : local_var_info_;
size_t old_capacity = var_info.size();
size_t index = is_global ? AsmJsScanner::GlobalIndex(token)
: AsmJsScanner::LocalIndex(token);
if (is_global && index + 1 > num_globals_) num_globals_ = index + 1;
if (index + 1 > old_capacity) {
size_t new_size = std::max(2 * old_capacity, index + 1);
Vector<VarInfo> new_info{zone_->NewArray<VarInfo>(new_size), new_size};
std::uninitialized_fill(new_info.begin(), new_info.end(), VarInfo{});
std::copy(var_info.begin(), var_info.end(), new_info.begin());
var_info = new_info;
}
return &var_info[index];
}
uint32_t AsmJsParser::VarIndex(VarInfo* info) {
......@@ -365,7 +349,7 @@ void AsmJsParser::ValidateModule() {
EXPECT_TOKEN('}');
// Check that all functions were eventually defined.
for (auto& info : global_var_info_) {
for (auto& info : global_var_info_.SubVector(0, num_globals_)) {
if (info.kind == VarKind::kFunction && !info.function_defined) {
FAIL("Undefined function");
}
......@@ -837,7 +821,7 @@ void AsmJsParser::ValidateFunction() {
}
scanner_.ResetLocals();
local_var_info_.clear();
std::fill(local_var_info_.begin(), local_var_info_.end(), VarInfo{});
}
// 6.4 ValidateFunction
......
......@@ -168,11 +168,12 @@ class AsmJsParser {
AsmJsScanner scanner_;
WasmModuleBuilder* module_builder_;
WasmFunctionBuilder* current_function_builder_;
AsmType* return_type_;
AsmType* return_type_ = nullptr;
uintptr_t stack_limit_;
StdlibSet stdlib_uses_;
ZoneVector<VarInfo> global_var_info_;
ZoneVector<VarInfo> local_var_info_;
Vector<VarInfo> global_var_info_;
Vector<VarInfo> local_var_info_;
size_t num_globals_ = 0;
CachedVectors<ValueType> cached_valuetype_vectors_{zone_};
CachedVectors<AsmType*> cached_asm_type_p_vectors_{zone_};
......@@ -184,20 +185,20 @@ class AsmJsParser {
int function_temp_locals_depth_;
// Error Handling related
bool failed_;
bool failed_ = false;
const char* failure_message_;
int failure_location_;
int failure_location_ = kNoSourcePosition;
// Module Related.
AsmJsScanner::token_t stdlib_name_;
AsmJsScanner::token_t foreign_name_;
AsmJsScanner::token_t heap_name_;
AsmJsScanner::token_t stdlib_name_ = kTokenNone;
AsmJsScanner::token_t foreign_name_ = kTokenNone;
AsmJsScanner::token_t heap_name_ = kTokenNone;
static const AsmJsScanner::token_t kTokenNone = 0;
// Track if parsing a heap assignment.
bool inside_heap_assignment_;
AsmType* heap_access_type_;
bool inside_heap_assignment_ = false;
AsmType* heap_access_type_ = nullptr;
ZoneVector<BlockInfo> block_stack_;
......@@ -214,7 +215,7 @@ class AsmJsParser {
// When making calls, the return type is needed to lookup signatures.
// For `+callsite(..)` or `fround(callsite(..))` use this value to pass
// along the coercion.
AsmType* call_coercion_;
AsmType* call_coercion_ = nullptr;
// The source position associated with the above {call_coercion}.
size_t call_coercion_position_;
......@@ -222,7 +223,7 @@ class AsmJsParser {
// When making calls, the coercion can also appear in the source stream
// syntactically "behind" the call site. For `callsite(..)|0` use this
// value to flag that such a coercion must happen.
AsmType* call_coercion_deferred_;
AsmType* call_coercion_deferred_ = nullptr;
// The source position at which requesting a deferred coercion via the
// aforementioned {call_coercion_deferred} is allowed.
......@@ -238,7 +239,7 @@ class AsmJsParser {
// Used to track the last label we've seen so it can be matched to later
// statements it's attached to.
AsmJsScanner::token_t pending_label_;
AsmJsScanner::token_t pending_label_ = kTokenNone;
// Global imports. The list of imported variables that are copied during
// module instantiation into a corresponding global variable.
......
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