Commit e7e10aa7 authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

[snapshot] Sanitize isolate during serialization

The isolate snapshot must not contain context-dependent objects, thus
root visitation must not reach context-dependent objects. This CL
sanitizes the isolate around serialization by clearing & later
restoring two lists: 1. feedback vectors for profiling tools, 2.
detached contexts.

Drive-by: Set an array buffer allocator for
SerializeDeserializeAndVerify.
Drive-by: Allow serialization of *another* native context when
serializing a native context.

Bug: v8:10416,v8:10493
Change-Id: I1c49bda364eccd6d44f9499a9926f4bcd31f665d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2179008Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarDan Elphick <delphick@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#67584}
parent 81439fba
......@@ -6200,6 +6200,10 @@ void Heap::SetBuiltinsConstantsTable(FixedArray cache) {
set_builtins_constants_table(cache);
}
void Heap::SetDetachedContexts(WeakArrayList detached_contexts) {
set_detached_contexts(detached_contexts);
}
void Heap::SetInterpreterEntryTrampolineForProfiling(Code code) {
DCHECK_EQ(Builtins::kInterpreterEntryTrampoline, code.builtin_index());
set_interpreter_entry_trampoline_for_profiling(code);
......
......@@ -813,6 +813,7 @@ class Heap {
void UnregisterStrongRoots(FullObjectSlot start);
void SetBuiltinsConstantsTable(FixedArray cache);
void SetDetachedContexts(WeakArrayList detached_contexts);
// A full copy of the interpreter entry trampoline, used as a template to
// create copies of the builtin at runtime. The copies are used to create
......
......@@ -120,6 +120,15 @@ void ContextSerializer::Serialize(Context* o,
void ContextSerializer::SerializeObject(HeapObject obj) {
DCHECK(!ObjectIsBytecodeHandler(obj)); // Only referenced in dispatch table.
if (!allow_active_isolate_for_testing()) {
// When serializing a snapshot intended for real use, we should not end up
// at another native context.
// But in test scenarios there is no way to avoid this. Since we only
// serialize a single context in these cases, and this context does not
// have to be executable, we can simply ignore this.
DCHECK_IMPLIES(obj.IsNativeContext(), obj == context_);
}
if (SerializeHotObject(obj)) return;
if (SerializeRoot(obj)) return;
......@@ -144,8 +153,6 @@ void ContextSerializer::SerializeObject(HeapObject obj) {
DCHECK(!obj.IsInternalizedString());
// Function and object templates are not context specific.
DCHECK(!obj.IsTemplateInfo());
// We should not end up at another native context.
DCHECK_IMPLIES(obj != context_, !obj.IsNativeContext());
// Clear literal boilerplates and feedback.
if (obj.IsFeedbackVector()) FeedbackVector::cast(obj).ClearSlots(isolate());
......
......@@ -217,6 +217,8 @@ void Snapshot::SerializeDeserializeAndVerifyForTesting(
new_isolate->enable_serializer();
new_isolate->Enter();
new_isolate->set_snapshot_blob(&serialized_data);
new_isolate->set_array_buffer_allocator(
v8::ArrayBuffer::Allocator::NewDefaultAllocator());
CHECK(Snapshot::Initialize(new_isolate));
HandleScope scope(new_isolate);
......@@ -272,7 +274,7 @@ v8::StartupData Snapshot::Create(
read_only_serializer.SerializeReadOnlyRoots();
StartupSerializer startup_serializer(isolate, flags, &read_only_serializer);
startup_serializer.SerializeStrongReferences();
startup_serializer.SerializeStrongReferences(no_gc);
// Serialize each context with a new serializer.
const int num_contexts = static_cast<int>(contexts->size());
......
......@@ -19,6 +19,49 @@
namespace v8 {
namespace internal {
namespace {
// The isolate roots may not point at context-specific objects during
// serialization.
class SanitizeIsolateScope final {
public:
SanitizeIsolateScope(Isolate* isolate, bool allow_active_isolate_for_testing,
const DisallowHeapAllocation& no_gc)
: isolate_(isolate),
feedback_vectors_for_profiling_tools_(
isolate->heap()->feedback_vectors_for_profiling_tools()),
detached_contexts_(isolate->heap()->detached_contexts()) {
#ifdef DEBUG
if (!allow_active_isolate_for_testing) {
// These should already be empty when creating a real snapshot.
DCHECK_EQ(feedback_vectors_for_profiling_tools_,
ReadOnlyRoots(isolate).undefined_value());
DCHECK_EQ(detached_contexts_,
ReadOnlyRoots(isolate).empty_weak_array_list());
}
#endif
isolate->SetFeedbackVectorsForProfilingTools(
ReadOnlyRoots(isolate).undefined_value());
isolate->heap()->SetDetachedContexts(
ReadOnlyRoots(isolate).empty_weak_array_list());
}
~SanitizeIsolateScope() {
// Restore saved fields.
isolate_->SetFeedbackVectorsForProfilingTools(
feedback_vectors_for_profiling_tools_);
isolate_->heap()->SetDetachedContexts(detached_contexts_);
}
private:
Isolate* isolate_;
const Object feedback_vectors_for_profiling_tools_;
const WeakArrayList detached_contexts_;
};
} // namespace
StartupSerializer::StartupSerializer(Isolate* isolate,
Snapshot::SerializerFlags flags,
ReadOnlySerializer* read_only_serializer)
......@@ -141,7 +184,8 @@ void StartupSerializer::SerializeWeakReferencesAndDeferred() {
Pad();
}
void StartupSerializer::SerializeStrongReferences() {
void StartupSerializer::SerializeStrongReferences(
const DisallowHeapAllocation& no_gc) {
Isolate* isolate = this->isolate();
// No active threads.
CHECK_NULL(isolate->thread_manager()->FirstThreadStateInUse());
......@@ -149,6 +193,9 @@ void StartupSerializer::SerializeStrongReferences() {
CHECK_IMPLIES(!allow_active_isolate_for_testing(),
isolate->handle_scope_implementer()->blocks()->empty());
SanitizeIsolateScope sanitize_isolate(
isolate, allow_active_isolate_for_testing(), no_gc);
// Visit smi roots and immortal immovables first to make sure they end up in
// the first page.
isolate->heap()->IterateSmiRoots(this);
......
......@@ -27,7 +27,7 @@ class V8_EXPORT_PRIVATE StartupSerializer : public RootsSerializer {
// 2) Builtins and bytecode handlers
// 3) Startup object cache
// 4) Weak references (e.g. the string table)
void SerializeStrongReferences();
void SerializeStrongReferences(const DisallowHeapAllocation& no_gc);
void SerializeWeakReferencesAndDeferred();
// If |obj| can be serialized in the read-only snapshot then add it to the
......
......@@ -171,13 +171,14 @@ static StartupBlobs Serialize(v8::Isolate* isolate) {
internal_isolate->heap()->CollectAllAvailableGarbage(
i::GarbageCollectionReason::kTesting);
DisallowHeapAllocation no_gc;
ReadOnlySerializer read_only_serializer(internal_isolate,
Snapshot::kDefaultSerializerFlags);
read_only_serializer.SerializeReadOnlyRoots();
StartupSerializer ser(internal_isolate, Snapshot::kDefaultSerializerFlags,
&read_only_serializer);
ser.SerializeStrongReferences();
ser.SerializeStrongReferences(no_gc);
ser.SerializeWeakReferencesAndDeferred();
read_only_serializer.FinalizeSerialization();
......@@ -390,7 +391,7 @@ static void SerializeContext(Vector<const byte>* startup_blob_out,
SnapshotByteSink startup_sink;
StartupSerializer startup_serializer(
isolate, Snapshot::kDefaultSerializerFlags, &read_only_serializer);
startup_serializer.SerializeStrongReferences();
startup_serializer.SerializeStrongReferences(no_gc);
SnapshotByteSink context_sink;
ContextSerializer context_serializer(
......@@ -540,7 +541,7 @@ static void SerializeCustomContext(Vector<const byte>* startup_blob_out,
SnapshotByteSink startup_sink;
StartupSerializer startup_serializer(
isolate, Snapshot::kDefaultSerializerFlags, &read_only_serializer);
startup_serializer.SerializeStrongReferences();
startup_serializer.SerializeStrongReferences(no_gc);
SnapshotByteSink context_sink;
ContextSerializer context_serializer(
......
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