35fc0c17c9
Due to the consistent overhead of snapshot checksum verification we ideally want to avoid it all-together. However there are still enough devices out there that suffer from corrupted snapshots that might cause hard to debug heap corruptions. This CL exposes the calculated (dummy value for now) and the expected snapshot checksum as a crash key, so it can be easily consulted during investigation. Note: The calculated crash key contains 0x0 for now as a dummy value. We will come up with a strategy later-on to limit the overhead of calculating the checksum. Bug: v8:12195 Change-Id: I6da6d74c035cb6f9b0edae212a36e6c41c048a5b Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3605813 Reviewed-by: Jakob Linke <jgruber@chromium.org> Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Commit-Queue: Camillo Bruni <cbruni@chromium.org> Cr-Commit-Position: refs/heads/main@{#80325}
151 lines
5.2 KiB
C++
151 lines
5.2 KiB
C++
// Copyright 2017 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "src/execution/isolate.h"
|
|
|
|
#include "include/libplatform/libplatform.h"
|
|
#include "include/v8-platform.h"
|
|
#include "include/v8-template.h"
|
|
#include "src/base/macros.h"
|
|
#include "src/base/platform/semaphore.h"
|
|
#include "src/execution/execution.h"
|
|
#include "src/init/v8.h"
|
|
#include "test/unittests/test-utils.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
|
|
namespace v8 {
|
|
|
|
using IsolateTest = TestWithIsolate;
|
|
|
|
namespace {
|
|
|
|
class MemoryPressureTask : public v8::Task {
|
|
public:
|
|
MemoryPressureTask(Isolate* isolate, base::Semaphore* semaphore)
|
|
: isolate_(isolate), semaphore_(semaphore) {}
|
|
~MemoryPressureTask() override = default;
|
|
MemoryPressureTask(const MemoryPressureTask&) = delete;
|
|
MemoryPressureTask& operator=(const MemoryPressureTask&) = delete;
|
|
|
|
// v8::Task implementation.
|
|
void Run() override {
|
|
isolate_->MemoryPressureNotification(MemoryPressureLevel::kCritical);
|
|
semaphore_->Signal();
|
|
}
|
|
|
|
private:
|
|
Isolate* isolate_;
|
|
base::Semaphore* semaphore_;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
// Check that triggering a memory pressure notification on the isolate thread
|
|
// doesn't request a GC interrupt.
|
|
TEST_F(IsolateTest, MemoryPressureNotificationForeground) {
|
|
internal::Isolate* i_isolate =
|
|
reinterpret_cast<internal::Isolate*>(isolate());
|
|
|
|
ASSERT_FALSE(i_isolate->stack_guard()->CheckGC());
|
|
isolate()->MemoryPressureNotification(MemoryPressureLevel::kCritical);
|
|
ASSERT_FALSE(i_isolate->stack_guard()->CheckGC());
|
|
}
|
|
|
|
// Check that triggering a memory pressure notification on an background thread
|
|
// requests a GC interrupt.
|
|
TEST_F(IsolateTest, MemoryPressureNotificationBackground) {
|
|
internal::Isolate* i_isolate =
|
|
reinterpret_cast<internal::Isolate*>(isolate());
|
|
|
|
base::Semaphore semaphore(0);
|
|
|
|
internal::V8::GetCurrentPlatform()->CallOnWorkerThread(
|
|
std::make_unique<MemoryPressureTask>(isolate(), &semaphore));
|
|
|
|
semaphore.Wait();
|
|
|
|
ASSERT_TRUE(i_isolate->stack_guard()->CheckGC());
|
|
v8::platform::PumpMessageLoop(internal::V8::GetCurrentPlatform(), isolate());
|
|
}
|
|
|
|
using IncumbentContextTest = TestWithIsolate;
|
|
|
|
// Check that Isolate::GetIncumbentContext() returns the correct one in basic
|
|
// scenarios.
|
|
TEST_F(IncumbentContextTest, Basic) {
|
|
auto Str = [&](const char* s) {
|
|
return String::NewFromUtf8(isolate(), s).ToLocalChecked();
|
|
};
|
|
auto Run = [&](Local<Context> context, const char* script) {
|
|
Context::Scope scope(context);
|
|
return Script::Compile(context, Str(script))
|
|
.ToLocalChecked()
|
|
->Run(context)
|
|
.ToLocalChecked();
|
|
};
|
|
|
|
// Set up the test environment; three contexts with getIncumbentGlobal()
|
|
// function.
|
|
Local<FunctionTemplate> get_incumbent_global = FunctionTemplate::New(
|
|
isolate(), [](const FunctionCallbackInfo<Value>& info) {
|
|
Local<Context> incumbent_context =
|
|
info.GetIsolate()->GetIncumbentContext();
|
|
info.GetReturnValue().Set(incumbent_context->Global());
|
|
});
|
|
Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate());
|
|
global_template->Set(isolate(), "getIncumbentGlobal", get_incumbent_global);
|
|
|
|
Local<Context> context_a = Context::New(isolate(), nullptr, global_template);
|
|
Local<Context> context_b = Context::New(isolate(), nullptr, global_template);
|
|
Local<Context> context_c = Context::New(isolate(), nullptr, global_template);
|
|
Local<Object> global_a = context_a->Global();
|
|
Local<Object> global_b = context_b->Global();
|
|
Local<Object> global_c = context_c->Global();
|
|
|
|
Local<String> security_token = Str("security_token");
|
|
context_a->SetSecurityToken(security_token);
|
|
context_b->SetSecurityToken(security_token);
|
|
context_c->SetSecurityToken(security_token);
|
|
|
|
global_a->Set(context_a, Str("b"), global_b).ToChecked();
|
|
global_b->Set(context_b, Str("c"), global_c).ToChecked();
|
|
|
|
// Test scenario 2: A -> B -> C, then the incumbent is C.
|
|
Run(context_a, "funcA = function() { return b.funcB(); }");
|
|
Run(context_b, "funcB = function() { return c.getIncumbentGlobal(); }");
|
|
// Without BackupIncumbentScope.
|
|
EXPECT_EQ(global_b, Run(context_a, "funcA()"));
|
|
{
|
|
// With BackupIncumbentScope.
|
|
Context::BackupIncumbentScope backup_incumbent(context_a);
|
|
EXPECT_EQ(global_b, Run(context_a, "funcA()"));
|
|
}
|
|
|
|
// Test scenario 2: A -> B -> C -> C, then the incumbent is C.
|
|
Run(context_a, "funcA = function() { return b.funcB(); }");
|
|
Run(context_b, "funcB = function() { return c.funcC(); }");
|
|
Run(context_c, "funcC = function() { return getIncumbentGlobal(); }");
|
|
// Without BackupIncumbentScope.
|
|
EXPECT_EQ(global_c, Run(context_a, "funcA()"));
|
|
{
|
|
// With BackupIncumbentScope.
|
|
Context::BackupIncumbentScope backup_incumbent(context_a);
|
|
EXPECT_EQ(global_c, Run(context_a, "funcA()"));
|
|
}
|
|
}
|
|
|
|
namespace {
|
|
thread_local std::map<v8::CrashKeyId, std::string> crash_keys;
|
|
void CrashKeyCallback(v8::CrashKeyId id, const std::string& value) {
|
|
EXPECT_EQ(crash_keys.count(id), 0u);
|
|
crash_keys[id] = value;
|
|
}
|
|
} // namespace
|
|
TEST_F(IsolateTest, SetAddCrashKeyCallback) {
|
|
isolate()->SetAddCrashKeyCallback(CrashKeyCallback);
|
|
EXPECT_EQ(crash_keys.size(), 6u);
|
|
}
|
|
|
|
} // namespace v8
|