[wasm][debug] Avoid use-after-free on tier down

When tiering down (or up), we first get a list of all native modules
(under a lock), then tier them down/up without holding the lock. Since
we don't hold (shared) ownership of the native module, it could die
in-between.
This CL fixes this by keeping weak pointers to the native modules, and
re-gaining a shared pointer before putting the module in the list of
modules to be tiered down/up.

R=thibaudm@chromium.org

Bug: v8:10588
Change-Id: I2891c3729f42f26d4026f3e2448e124863b95122
Cq-Include-Trybots: luci.v8.try:v8_linux64_tsan_rel
Cq-Include-Trybots: luci.v8.try:v8_linux64_tsan_isolates_rel_ng
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2228515
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Reviewed-by: Thibaud Michaud <thibaudm@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68145}
This commit is contained in:
Clemens Backes 2020-06-03 15:50:21 +02:00 committed by Commit Bot
parent 246344ad2c
commit 0816423d59

View File

@ -344,9 +344,8 @@ struct WasmEngine::IsolateInfo {
}
#endif
// All native modules that are being used by this Isolate (currently only
// grows, never shrinks).
std::set<NativeModule*> native_modules;
// All native modules that are being used by this Isolate.
std::unordered_map<NativeModule*, std::weak_ptr<NativeModule>> native_modules;
// Scripts created for each native module in this isolate.
std::unordered_map<NativeModule*, WeakScriptHandle> scripts;
@ -621,17 +620,19 @@ void WasmEngine::CompileFunction(Isolate* isolate, NativeModule* native_module,
}
void WasmEngine::TierDownAllModulesPerIsolate(Isolate* isolate) {
std::vector<NativeModule*> native_modules;
std::vector<std::shared_ptr<NativeModule>> native_modules;
{
base::MutexGuard lock(&mutex_);
if (isolates_[isolate]->keep_tiered_down) return;
isolates_[isolate]->keep_tiered_down = true;
for (auto* native_module : isolates_[isolate]->native_modules) {
native_modules.push_back(native_module);
native_module->SetTieringState(kTieredDown);
for (auto& entry : isolates_[isolate]->native_modules) {
entry.first->SetTieringState(kTieredDown);
if (auto shared_ptr = entry.second.lock()) {
native_modules.emplace_back(std::move(shared_ptr));
}
}
}
for (auto* native_module : native_modules) {
for (auto& native_module : native_modules) {
native_module->TriggerRecompilation();
}
}
@ -639,7 +640,7 @@ void WasmEngine::TierDownAllModulesPerIsolate(Isolate* isolate) {
void WasmEngine::TierUpAllModulesPerIsolate(Isolate* isolate) {
// Only trigger recompilation after releasing the mutex, otherwise we risk
// deadlocks because of lock inversion.
std::vector<NativeModule*> native_modules_to_recompile;
std::vector<std::shared_ptr<NativeModule>> native_modules_to_recompile;
{
base::MutexGuard lock(&mutex_);
isolates_[isolate]->keep_tiered_down = false;
@ -651,16 +652,19 @@ void WasmEngine::TierUpAllModulesPerIsolate(Isolate* isolate) {
}
return false;
};
for (auto* native_module : isolates_[isolate]->native_modules) {
for (auto& entry : isolates_[isolate]->native_modules) {
auto* native_module = entry.first;
if (!native_module->IsTieredDown()) continue;
// Only start tier-up if no other isolate needs this modules in tiered
// down state.
if (test_keep_tiered_down(native_module)) continue;
native_module->SetTieringState(kTieredUp);
native_modules_to_recompile.push_back(native_module);
if (auto shared_ptr = entry.second.lock()) {
native_modules_to_recompile.emplace_back(std::move(shared_ptr));
}
}
}
for (auto* native_module : native_modules_to_recompile) {
for (auto& native_module : native_modules_to_recompile) {
native_module->TriggerRecompilation();
}
}
@ -767,11 +771,12 @@ Handle<WasmModuleObject> WasmEngine::ImportNativeModule(
Handle<FixedArray> export_wrappers;
CompileJsToWasmWrappers(isolate, native_module->module(), &export_wrappers);
Handle<WasmModuleObject> module_object = WasmModuleObject::New(
isolate, std::move(shared_native_module), script, export_wrappers);
isolate, shared_native_module, script, export_wrappers);
{
base::MutexGuard lock(&mutex_);
DCHECK_EQ(1, isolates_.count(isolate));
isolates_[isolate]->native_modules.insert(native_module);
isolates_[isolate]->native_modules.emplace(native_module,
std::move(shared_native_module));
DCHECK_EQ(1, native_modules_.count(native_module));
native_modules_[native_module]->isolates.insert(isolate);
}
@ -890,8 +895,8 @@ void WasmEngine::AddIsolate(Isolate* isolate) {
WasmEngine* engine = isolate->wasm_engine();
base::MutexGuard lock(&engine->mutex_);
DCHECK_EQ(1, engine->isolates_.count(isolate));
for (auto* native_module : engine->isolates_[isolate]->native_modules) {
native_module->SampleCodeSize(counters, NativeModule::kSampling);
for (auto& entry : engine->isolates_[isolate]->native_modules) {
entry.first->SampleCodeSize(counters, NativeModule::kSampling);
}
};
isolate->heap()->AddGCEpilogueCallback(callback, v8::kGCTypeMarkSweepCompact,
@ -915,7 +920,8 @@ void WasmEngine::RemoveIsolate(Isolate* isolate) {
DCHECK_NE(isolates_.end(), it);
std::unique_ptr<IsolateInfo> info = std::move(it->second);
isolates_.erase(it);
for (NativeModule* native_module : info->native_modules) {
for (auto& entry : info->native_modules) {
auto* native_module = entry.first;
DCHECK_EQ(1, native_modules_.count(native_module));
DCHECK_EQ(1, native_modules_[native_module]->isolates.count(isolate));
auto* info = native_modules_[native_module].get();
@ -1010,7 +1016,7 @@ std::shared_ptr<NativeModule> WasmEngine::NewNativeModule(
DCHECK(pair.second); // inserted new entry.
pair.first->second.get()->isolates.insert(isolate);
auto& modules_per_isolate = isolates_[isolate]->native_modules;
modules_per_isolate.insert(native_module.get());
modules_per_isolate.emplace(native_module.get(), native_module);
if (isolates_[isolate]->keep_tiered_down) {
native_module->SetTieringState(kTieredDown);
}
@ -1033,7 +1039,8 @@ std::shared_ptr<NativeModule> WasmEngine::MaybeGetNativeModule(
native_module_info = std::make_unique<NativeModuleInfo>();
}
native_module_info->isolates.insert(isolate);
isolates_[isolate]->native_modules.insert(native_module.get());
isolates_[isolate]->native_modules.emplace(native_module.get(),
native_module);
if (isolates_[isolate]->keep_tiered_down) {
native_module->SetTieringState(kTieredDown);
recompile_module = true;
@ -1062,7 +1069,8 @@ bool WasmEngine::UpdateNativeModuleCache(
DCHECK_EQ(1, native_modules_.count(native_module->get()));
native_modules_[native_module->get()]->isolates.insert(isolate);
DCHECK_EQ(1, isolates_.count(isolate));
isolates_[isolate]->native_modules.insert(native_module->get());
isolates_[isolate]->native_modules.emplace(native_module->get(),
*native_module);
if (isolates_[isolate]->keep_tiered_down) {
native_module->get()->SetTieringState(kTieredDown);
recompile_module = true;