Commit abbaac48 authored by yangguo's avatar yangguo Committed by Commit bot

Reland "Prevent stack overflow in the serializer/deserializer."

TBR=mvstanton@chromium.org

Review URL: https://codereview.chromium.org/1124403006

Cr-Commit-Position: refs/heads/master@{#28415}
parent 6dd52eaf
...@@ -379,7 +379,7 @@ StartupData V8::CreateSnapshotDataBlob(const char* custom_source) { ...@@ -379,7 +379,7 @@ StartupData V8::CreateSnapshotDataBlob(const char* custom_source) {
i::SnapshotByteSink context_sink; i::SnapshotByteSink context_sink;
i::PartialSerializer context_ser(internal_isolate, &ser, &context_sink); i::PartialSerializer context_ser(internal_isolate, &ser, &context_sink);
context_ser.Serialize(&raw_context); context_ser.Serialize(&raw_context);
ser.SerializeWeakReferences(); ser.SerializeWeakReferencesAndDeferred();
result = i::Snapshot::CreateSnapshotBlob(ser, context_ser, metadata); result = i::Snapshot::CreateSnapshotBlob(ser, context_ser, metadata);
} }
......
...@@ -2831,6 +2831,7 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from, ...@@ -2831,6 +2831,7 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
if (value->IsPropertyCell()) { if (value->IsPropertyCell()) {
value = handle(PropertyCell::cast(*value)->value(), isolate()); value = handle(PropertyCell::cast(*value)->value(), isolate());
} }
if (value->IsTheHole()) continue;
PropertyDetails details = properties->DetailsAt(i); PropertyDetails details = properties->DetailsAt(i);
DCHECK_EQ(kData, details.kind()); DCHECK_EQ(kData, details.kind());
JSObject::AddProperty(to, key, value, details.attributes()); JSObject::AddProperty(to, key, value, details.attributes());
......
...@@ -14689,9 +14689,10 @@ Handle<Derived> HashTable<Derived, Shape, Key>::New( ...@@ -14689,9 +14689,10 @@ Handle<Derived> HashTable<Derived, Shape, Key>::New(
PretenureFlag pretenure) { PretenureFlag pretenure) {
DCHECK(0 <= at_least_space_for); DCHECK(0 <= at_least_space_for);
DCHECK(!capacity_option || base::bits::IsPowerOfTwo32(at_least_space_for)); DCHECK(!capacity_option || base::bits::IsPowerOfTwo32(at_least_space_for));
int capacity = (capacity_option == USE_CUSTOM_MINIMUM_CAPACITY) int capacity =
(capacity_option == USE_CUSTOM_MINIMUM_CAPACITY)
? at_least_space_for ? at_least_space_for
: isolate->serializer_enabled() : isolate->serializer_enabled() && isolate->bootstrapper()->IsActive()
? ComputeCapacityForSerialization(at_least_space_for) ? ComputeCapacityForSerialization(at_least_space_for)
: ComputeCapacity(at_least_space_for); : ComputeCapacity(at_least_space_for);
if (capacity > HashTable::kMaxCapacity) { if (capacity > HashTable::kMaxCapacity) {
......
This diff is collapsed.
...@@ -306,6 +306,10 @@ class SerializerDeserializer: public ObjectVisitor { ...@@ -306,6 +306,10 @@ class SerializerDeserializer: public ObjectVisitor {
static const int kNumberOfSpaces = LAST_SPACE + 1; static const int kNumberOfSpaces = LAST_SPACE + 1;
protected: protected:
static bool CanBeDeferred(HeapObject* o) {
return !o->IsString() && !o->IsScript();
}
// ---------- byte code range 0x00..0x7f ---------- // ---------- byte code range 0x00..0x7f ----------
// Byte codes in this range represent Where, HowToCode and WhereToPoint. // Byte codes in this range represent Where, HowToCode and WhereToPoint.
// Where the pointed-to object can be found: // Where the pointed-to object can be found:
...@@ -373,6 +377,8 @@ class SerializerDeserializer: public ObjectVisitor { ...@@ -373,6 +377,8 @@ class SerializerDeserializer: public ObjectVisitor {
static const int kNop = 0x3d; static const int kNop = 0x3d;
// Move to next reserved chunk. // Move to next reserved chunk.
static const int kNextChunk = 0x3e; static const int kNextChunk = 0x3e;
// Deferring object content.
static const int kDeferred = 0x3f;
// A tag emitted at strategic points in the snapshot to delineate sections. // A tag emitted at strategic points in the snapshot to delineate sections.
// If the deserializer does not find these at the expected moments then it // If the deserializer does not find these at the expected moments then it
// is an indication that the snapshot and the VM do not fit together. // is an indication that the snapshot and the VM do not fit together.
...@@ -553,22 +559,22 @@ class Deserializer: public SerializerDeserializer { ...@@ -553,22 +559,22 @@ class Deserializer: public SerializerDeserializer {
memcpy(dest, src, sizeof(*src)); memcpy(dest, src, sizeof(*src));
} }
// Allocation sites are present in the snapshot, and must be linked into void DeserializeDeferredObjects();
// a list at deserialization time.
void RelinkAllocationSite(AllocationSite* site);
// Fills in some heap data in an area from start to end (non-inclusive). The // Fills in some heap data in an area from start to end (non-inclusive). The
// space id is used for the write barrier. The object_address is the address // space id is used for the write barrier. The object_address is the address
// of the object we are writing into, or NULL if we are not writing into an // of the object we are writing into, or NULL if we are not writing into an
// object, i.e. if we are writing a series of tagged values that are not on // object, i.e. if we are writing a series of tagged values that are not on
// the heap. // the heap. Return false if the object content has been deferred.
void ReadData(Object** start, Object** end, int space, bool ReadData(Object** start, Object** end, int space,
Address object_address); Address object_address);
void ReadObject(int space_number, Object** write_back); void ReadObject(int space_number, Object** write_back);
Address Allocate(int space_index, int size); Address Allocate(int space_index, int size);
// Special handling for serialized code like hooking up internalized strings. // Special handling for serialized code like hooking up internalized strings.
HeapObject* ProcessNewObjectFromSerializedCode(HeapObject* obj); HeapObject* PostProcessNewObject(HeapObject* obj);
void RelinkAllocationSite(AllocationSite* obj);
// This returns the address of an object that has been described in the // This returns the address of an object that has been described in the
// snapshot by chunk index and offset. // snapshot by chunk index and offset.
...@@ -612,6 +618,8 @@ class Serializer : public SerializerDeserializer { ...@@ -612,6 +618,8 @@ class Serializer : public SerializerDeserializer {
void EncodeReservations(List<SerializedData::Reservation>* out) const; void EncodeReservations(List<SerializedData::Reservation>* out) const;
void SerializeDeferredObjects();
Isolate* isolate() const { return isolate_; } Isolate* isolate() const { return isolate_; }
BackReferenceMap* back_reference_map() { return &back_reference_map_; } BackReferenceMap* back_reference_map() { return &back_reference_map_; }
...@@ -634,6 +642,7 @@ class Serializer : public SerializerDeserializer { ...@@ -634,6 +642,7 @@ class Serializer : public SerializerDeserializer {
is_code_object_(o->IsCode()), is_code_object_(o->IsCode()),
code_has_been_output_(false) {} code_has_been_output_(false) {}
void Serialize(); void Serialize();
void SerializeDeferred();
void VisitPointers(Object** start, Object** end); void VisitPointers(Object** start, Object** end);
void VisitEmbeddedPointer(RelocInfo* target); void VisitEmbeddedPointer(RelocInfo* target);
void VisitExternalReference(Address* p); void VisitExternalReference(Address* p);
...@@ -675,12 +684,29 @@ class Serializer : public SerializerDeserializer { ...@@ -675,12 +684,29 @@ class Serializer : public SerializerDeserializer {
bool code_has_been_output_; bool code_has_been_output_;
}; };
class RecursionScope {
public:
explicit RecursionScope(Serializer* serializer) : serializer_(serializer) {
serializer_->recursion_depth_++;
}
~RecursionScope() { serializer_->recursion_depth_--; }
bool ExceedsMaximum() {
return serializer_->recursion_depth_ >= kMaxRecursionDepth;
}
private:
static const int kMaxRecursionDepth = 32;
Serializer* serializer_;
};
virtual void SerializeObject(HeapObject* o, HowToCode how_to_code, virtual void SerializeObject(HeapObject* o, HowToCode how_to_code,
WhereToPoint where_to_point, int skip) = 0; WhereToPoint where_to_point, int skip) = 0;
void PutRoot(int index, HeapObject* object, HowToCode how, WhereToPoint where, void PutRoot(int index, HeapObject* object, HowToCode how, WhereToPoint where,
int skip); int skip);
void PutBackReference(HeapObject* object, BackReference reference);
// Returns true if the object was successfully serialized. // Returns true if the object was successfully serialized.
bool SerializeKnownObject(HeapObject* obj, HowToCode how_to_code, bool SerializeKnownObject(HeapObject* obj, HowToCode how_to_code,
WhereToPoint where_to_point, int skip); WhereToPoint where_to_point, int skip);
...@@ -722,6 +748,11 @@ class Serializer : public SerializerDeserializer { ...@@ -722,6 +748,11 @@ class Serializer : public SerializerDeserializer {
SnapshotByteSink* sink() const { return sink_; } SnapshotByteSink* sink() const { return sink_; }
void QueueDeferredObject(HeapObject* obj) {
DCHECK(back_reference_map_.Lookup(obj).is_valid());
deferred_objects_.Add(obj);
}
void OutputStatistics(const char* name); void OutputStatistics(const char* name);
Isolate* isolate_; Isolate* isolate_;
...@@ -732,8 +763,11 @@ class Serializer : public SerializerDeserializer { ...@@ -732,8 +763,11 @@ class Serializer : public SerializerDeserializer {
BackReferenceMap back_reference_map_; BackReferenceMap back_reference_map_;
RootIndexMap root_index_map_; RootIndexMap root_index_map_;
int recursion_depth_;
friend class Deserializer; friend class Deserializer;
friend class ObjectSerializer; friend class ObjectSerializer;
friend class RecursionScope;
friend class SnapshotData; friend class SnapshotData;
private: private:
...@@ -752,6 +786,9 @@ class Serializer : public SerializerDeserializer { ...@@ -752,6 +786,9 @@ class Serializer : public SerializerDeserializer {
List<byte> code_buffer_; List<byte> code_buffer_;
// To handle stack overflow.
List<HeapObject*> deferred_objects_;
#ifdef OBJECT_PRINT #ifdef OBJECT_PRINT
static const int kInstanceTypes = 256; static const int kInstanceTypes = 256;
int* instance_type_count_; int* instance_type_count_;
...@@ -797,7 +834,7 @@ class PartialSerializer : public Serializer { ...@@ -797,7 +834,7 @@ class PartialSerializer : public Serializer {
void SerializeOutdatedContextsAsFixedArray(); void SerializeOutdatedContextsAsFixedArray();
Serializer* startup_serializer_; Serializer* startup_serializer_;
List<BackReference> outdated_contexts_; List<Context*> outdated_contexts_;
Object* global_object_; Object* global_object_;
PartialCacheIndexMap partial_cache_index_map_; PartialCacheIndexMap partial_cache_index_map_;
DISALLOW_COPY_AND_ASSIGN(PartialSerializer); DISALLOW_COPY_AND_ASSIGN(PartialSerializer);
...@@ -829,11 +866,10 @@ class StartupSerializer : public Serializer { ...@@ -829,11 +866,10 @@ class StartupSerializer : public Serializer {
virtual void SerializeStrongReferences(); virtual void SerializeStrongReferences();
virtual void SerializeObject(HeapObject* o, HowToCode how_to_code, virtual void SerializeObject(HeapObject* o, HowToCode how_to_code,
WhereToPoint where_to_point, int skip) override; WhereToPoint where_to_point, int skip) override;
void SerializeWeakReferences(); void SerializeWeakReferencesAndDeferred();
void Serialize() { void Serialize() {
SerializeStrongReferences(); SerializeStrongReferences();
SerializeWeakReferences(); SerializeWeakReferencesAndDeferred();
Pad();
} }
private: private:
......
...@@ -329,7 +329,7 @@ UNINITIALIZED_TEST(PartialSerialization) { ...@@ -329,7 +329,7 @@ UNINITIALIZED_TEST(PartialSerialization) {
&partial_sink); &partial_sink);
partial_serializer.Serialize(&raw_foo); partial_serializer.Serialize(&raw_foo);
startup_serializer.SerializeWeakReferences(); startup_serializer.SerializeWeakReferencesAndDeferred();
SnapshotData startup_snapshot(startup_serializer); SnapshotData startup_snapshot(startup_serializer);
SnapshotData partial_snapshot(partial_serializer); SnapshotData partial_snapshot(partial_serializer);
...@@ -447,7 +447,7 @@ UNINITIALIZED_TEST(ContextSerialization) { ...@@ -447,7 +447,7 @@ UNINITIALIZED_TEST(ContextSerialization) {
PartialSerializer partial_serializer(isolate, &startup_serializer, PartialSerializer partial_serializer(isolate, &startup_serializer,
&partial_sink); &partial_sink);
partial_serializer.Serialize(&raw_context); partial_serializer.Serialize(&raw_context);
startup_serializer.SerializeWeakReferences(); startup_serializer.SerializeWeakReferencesAndDeferred();
SnapshotData startup_snapshot(startup_serializer); SnapshotData startup_snapshot(startup_serializer);
SnapshotData partial_snapshot(partial_serializer); SnapshotData partial_snapshot(partial_serializer);
...@@ -582,7 +582,7 @@ UNINITIALIZED_TEST(CustomContextSerialization) { ...@@ -582,7 +582,7 @@ UNINITIALIZED_TEST(CustomContextSerialization) {
PartialSerializer partial_serializer(isolate, &startup_serializer, PartialSerializer partial_serializer(isolate, &startup_serializer,
&partial_sink); &partial_sink);
partial_serializer.Serialize(&raw_context); partial_serializer.Serialize(&raw_context);
startup_serializer.SerializeWeakReferences(); startup_serializer.SerializeWeakReferencesAndDeferred();
SnapshotData startup_snapshot(startup_serializer); SnapshotData startup_snapshot(startup_serializer);
SnapshotData partial_snapshot(partial_serializer); SnapshotData partial_snapshot(partial_serializer);
...@@ -738,6 +738,44 @@ TEST(PerIsolateSnapshotBlobsWithLocker) { ...@@ -738,6 +738,44 @@ TEST(PerIsolateSnapshotBlobsWithLocker) {
} }
TEST(SnapshotBlobsStackOverflow) {
DisableTurbofan();
const char* source =
"var a = [0];"
"var b = a;"
"for (var i = 0; i < 10000; i++) {"
" var c = [i];"
" b.push(c);"
" b.push(c);"
" b = c;"
"}";
v8::StartupData data = v8::V8::CreateSnapshotDataBlob(source);
v8::Isolate::CreateParams params;
params.snapshot_blob = &data;
params.array_buffer_allocator = CcTest::array_buffer_allocator();
v8::Isolate* isolate = v8::Isolate::New(params);
{
v8::Isolate::Scope i_scope(isolate);
v8::HandleScope h_scope(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate);
delete[] data.data; // We can dispose of the snapshot blob now.
v8::Context::Scope c_scope(context);
const char* test =
"var sum = 0;"
"while (a) {"
" sum += a[0];"
" a = a[1];"
"}"
"sum";
CHECK_EQ(9999 * 5000, CompileRun(test)->ToInt32(isolate)->Int32Value());
}
isolate->Dispose();
}
TEST(TestThatAlwaysSucceeds) { TEST(TestThatAlwaysSucceeds) {
} }
......
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