[wasm] Fix data race in code logging

In chromium, the platform might delete the task before executing it
and before fully deregistering the Isolate.
In that case we need to deregister it from the WasmEngine to avoid a
data race or use-after-free.

R=mstarzinger@chromium.org
CC=​​herhut@chromium.org

Bug: v8:8783, chromium:928458
Cq-Include-Trybots: luci.v8.try:v8_linux64_tsan_rel
Change-Id: Ie94e037f07fbe220505a5d8314b413f24c0990e1
Reviewed-on: https://chromium-review.googlesource.com/c/1454598
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: Michael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59372}
This commit is contained in:
Clemens Hammacher 2019-02-05 14:22:24 +01:00 committed by Commit Bot
parent e43668a570
commit fb89830271

View File

@ -25,22 +25,24 @@ namespace wasm {
namespace { namespace {
class LogCodesTask : public Task { class LogCodesTask : public Task {
public: public:
explicit LogCodesTask(base::Mutex* mutex, LogCodesTask** task_slot, LogCodesTask(base::Mutex* mutex, LogCodesTask** task_slot, Isolate* isolate)
Isolate* isolate) : mutex_(mutex), task_slot_(task_slot), isolate_(isolate) {
: mutex_(mutex), task_slot_(task_slot), isolate_(isolate) {} DCHECK_NOT_NULL(task_slot);
DCHECK_NOT_NULL(isolate);
}
~LogCodesTask() {
// If the platform deletes this task before executing it, we also deregister
// it to avoid use-after-free from still-running background threads.
if (!cancelled()) DeregisterTask();
}
// Hold the {mutex_} when calling this method. // Hold the {mutex_} when calling this method.
void AddCode(WasmCode* code) { code_to_log_.push_back(code); } void AddCode(WasmCode* code) { code_to_log_.push_back(code); }
void Run() override { void Run() override {
if (isolate_ == nullptr) return; // Cancelled. if (cancelled()) return;
// Remove this task from the {IsolateInfo} in the engine. The next DeregisterTask();
// logging request will allocate and schedule a new task.
{
base::MutexGuard guard(mutex_);
DCHECK_EQ(this, *task_slot_);
*task_slot_ = nullptr;
}
// If by now we should not log code any more, do not log it. // If by now we should not log code any more, do not log it.
if (!WasmCode::ShouldBeLogged(isolate_)) return; if (!WasmCode::ShouldBeLogged(isolate_)) return;
for (WasmCode* code : code_to_log_) { for (WasmCode* code : code_to_log_) {
@ -54,12 +56,27 @@ class LogCodesTask : public Task {
isolate_ = nullptr; isolate_ = nullptr;
} }
bool cancelled() const { return isolate_ == nullptr; }
void DeregisterTask() {
// The task will only be deregistered from the foreground thread (executing
// this task or calling its destructor), thus we do not need synchronization
// on this field access.
if (task_slot_ == nullptr) return; // already deregistered.
// Remove this task from the {IsolateInfo} in the engine. The next
// logging request will allocate and schedule a new task.
base::MutexGuard guard(mutex_);
DCHECK_EQ(this, *task_slot_);
*task_slot_ = nullptr;
task_slot_ = nullptr;
}
private: private:
// The mutex of the WasmEngine. // The mutex of the WasmEngine.
base::Mutex* const mutex_; base::Mutex* const mutex_;
// The slot in the WasmEngine where this LogCodesTask is stored. This is // The slot in the WasmEngine where this LogCodesTask is stored. This is
// cleared by this task before execution. // cleared by this task before execution or on task destruction.
LogCodesTask** const task_slot_; LogCodesTask** task_slot_;
Isolate* isolate_; Isolate* isolate_;
std::vector<WasmCode*> code_to_log_; std::vector<WasmCode*> code_to_log_;
}; };