Commit c478a229 authored by jkummerow's avatar jkummerow Committed by Commit bot

SnapshotCreator: start from existing snapshot if we have one

This requires serialized data to track the number of API-provided
external references separately.
And it flushes out a case of serialized data corruption (stored "length"
field too large) that we didn't handle without crashing.

BUG=v8:6055

Review-Url: https://codereview.chromium.org/2736923002
Cr-Commit-Position: refs/heads/master@{#43649}
parent 5a36af3c
...@@ -511,8 +511,11 @@ SnapshotCreator::SnapshotCreator(intptr_t* external_references, ...@@ -511,8 +511,11 @@ SnapshotCreator::SnapshotCreator(intptr_t* external_references,
internal_isolate->set_array_buffer_allocator(&data->allocator_); internal_isolate->set_array_buffer_allocator(&data->allocator_);
internal_isolate->set_api_external_references(external_references); internal_isolate->set_api_external_references(external_references);
isolate->Enter(); isolate->Enter();
if (existing_snapshot) { const StartupData* blob = existing_snapshot
internal_isolate->set_snapshot_blob(existing_snapshot); ? existing_snapshot
: i::Snapshot::DefaultSnapshotBlob();
if (blob && blob->raw_size > 0) {
internal_isolate->set_snapshot_blob(blob);
i::Snapshot::Initialize(internal_isolate); i::Snapshot::Initialize(internal_isolate);
} else { } else {
internal_isolate->Init(nullptr); internal_isolate->Init(nullptr);
......
...@@ -46,6 +46,7 @@ ExternalReferenceTable::ExternalReferenceTable(Isolate* isolate) { ...@@ -46,6 +46,7 @@ ExternalReferenceTable::ExternalReferenceTable(Isolate* isolate) {
AddAccessors(isolate); AddAccessors(isolate);
AddStubCache(isolate); AddStubCache(isolate);
AddDeoptEntries(isolate); AddDeoptEntries(isolate);
// API references must be added last.
AddApiReferences(isolate); AddApiReferences(isolate);
} }
......
...@@ -23,6 +23,7 @@ class ExternalReferenceTable { ...@@ -23,6 +23,7 @@ class ExternalReferenceTable {
Address address(uint32_t i) { return refs_[i].address; } Address address(uint32_t i) { return refs_[i].address; }
const char* name(uint32_t i) { return refs_[i].name; } const char* name(uint32_t i) { return refs_[i].name; }
bool is_api_reference(uint32_t i) { return i >= api_refs_start_; } bool is_api_reference(uint32_t i) { return i >= api_refs_start_; }
uint32_t num_api_references() { return size() - api_refs_start_; }
#ifdef DEBUG #ifdef DEBUG
void increment_count(uint32_t i) { refs_[i].count++; } void increment_count(uint32_t i) { refs_[i].count++; }
......
...@@ -387,6 +387,9 @@ SerializedCodeData::SerializedCodeData(const List<byte>* payload, ...@@ -387,6 +387,9 @@ SerializedCodeData::SerializedCodeData(const List<byte>* payload,
SetHeaderValue(kNumCodeStubKeysOffset, num_stub_keys); SetHeaderValue(kNumCodeStubKeysOffset, num_stub_keys);
SetHeaderValue(kPayloadLengthOffset, payload->length()); SetHeaderValue(kPayloadLengthOffset, payload->length());
// Zero out any padding in the header.
memset(data_ + kUnalignedHeaderSize, 0, kHeaderSize - kUnalignedHeaderSize);
// Copy reservation chunk sizes. // Copy reservation chunk sizes.
CopyBytes(data_ + kHeaderSize, reinterpret_cast<byte*>(reservations.begin()), CopyBytes(data_ + kHeaderSize, reinterpret_cast<byte*>(reservations.begin()),
reservation_size); reservation_size);
...@@ -395,6 +398,7 @@ SerializedCodeData::SerializedCodeData(const List<byte>* payload, ...@@ -395,6 +398,7 @@ SerializedCodeData::SerializedCodeData(const List<byte>* payload,
CopyBytes(data_ + kHeaderSize + reservation_size, CopyBytes(data_ + kHeaderSize + reservation_size,
reinterpret_cast<byte*>(stub_keys->begin()), stub_keys_size); reinterpret_cast<byte*>(stub_keys->begin()), stub_keys_size);
// Zero out any padding before the payload.
memset(data_ + payload_offset, 0, padded_payload_offset - payload_offset); memset(data_ + payload_offset, 0, padded_payload_offset - payload_offset);
// Copy serialized data. // Copy serialized data.
...@@ -411,10 +415,14 @@ SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck( ...@@ -411,10 +415,14 @@ SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
if (this->size_ < kHeaderSize) return INVALID_HEADER; if (this->size_ < kHeaderSize) return INVALID_HEADER;
uint32_t magic_number = GetMagicNumber(); uint32_t magic_number = GetMagicNumber();
if (magic_number != ComputeMagicNumber(isolate)) return MAGIC_NUMBER_MISMATCH; if (magic_number != ComputeMagicNumber(isolate)) return MAGIC_NUMBER_MISMATCH;
if (GetExtraReferences() > GetExtraReferences(isolate)) {
return MAGIC_NUMBER_MISMATCH;
}
uint32_t version_hash = GetHeaderValue(kVersionHashOffset); uint32_t version_hash = GetHeaderValue(kVersionHashOffset);
uint32_t source_hash = GetHeaderValue(kSourceHashOffset); uint32_t source_hash = GetHeaderValue(kSourceHashOffset);
uint32_t cpu_features = GetHeaderValue(kCpuFeaturesOffset); uint32_t cpu_features = GetHeaderValue(kCpuFeaturesOffset);
uint32_t flags_hash = GetHeaderValue(kFlagHashOffset); uint32_t flags_hash = GetHeaderValue(kFlagHashOffset);
uint32_t payload_length = GetHeaderValue(kPayloadLengthOffset);
uint32_t c1 = GetHeaderValue(kChecksum1Offset); uint32_t c1 = GetHeaderValue(kChecksum1Offset);
uint32_t c2 = GetHeaderValue(kChecksum2Offset); uint32_t c2 = GetHeaderValue(kChecksum2Offset);
if (version_hash != Version::Hash()) return VERSION_MISMATCH; if (version_hash != Version::Hash()) return VERSION_MISMATCH;
...@@ -423,6 +431,12 @@ SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck( ...@@ -423,6 +431,12 @@ SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
return CPU_FEATURES_MISMATCH; return CPU_FEATURES_MISMATCH;
} }
if (flags_hash != FlagList::Hash()) return FLAGS_MISMATCH; if (flags_hash != FlagList::Hash()) return FLAGS_MISMATCH;
uint32_t max_payload_length =
this->size_ -
POINTER_SIZE_ALIGN(kHeaderSize +
GetHeaderValue(kNumReservationsOffset) * kInt32Size +
GetHeaderValue(kNumCodeStubKeysOffset) * kInt32Size);
if (payload_length > max_payload_length) return LENGTH_MISMATCH;
if (!Checksum(DataWithoutHeader()).Check(c1, c2)) return CHECKSUM_MISMATCH; if (!Checksum(DataWithoutHeader()).Check(c1, c2)) return CHECKSUM_MISMATCH;
return CHECK_SUCCESS; return CHECK_SUCCESS;
} }
......
...@@ -85,24 +85,25 @@ class SerializedCodeData : public SerializedData { ...@@ -85,24 +85,25 @@ class SerializedCodeData : public SerializedData {
CPU_FEATURES_MISMATCH = 4, CPU_FEATURES_MISMATCH = 4,
FLAGS_MISMATCH = 5, FLAGS_MISMATCH = 5,
CHECKSUM_MISMATCH = 6, CHECKSUM_MISMATCH = 6,
INVALID_HEADER = 7 INVALID_HEADER = 7,
LENGTH_MISMATCH = 8
}; };
// The data header consists of uint32_t-sized entries: // The data header consists of uint32_t-sized entries:
// [0] magic number and external reference count // [0] magic number and (internally provided) external reference count
// [1] version hash // [1] extra (API-provided) external reference count
// [2] source hash // [2] version hash
// [3] cpu features // [3] source hash
// [4] flag hash // [4] cpu features
// [5] number of code stub keys // [5] flag hash
// [6] number of reservation size entries // [6] number of code stub keys
// [7] payload length // [7] number of reservation size entries
// [8] payload checksum part 1 // [8] payload length
// [9] payload checksum part 2 // [9] payload checksum part 1
// [10] payload checksum part 2
// ... reservations // ... reservations
// ... code stub keys // ... code stub keys
// ... serialized payload // ... serialized payload
static const int kVersionHashOffset = kMagicNumberOffset + kInt32Size;
static const int kSourceHashOffset = kVersionHashOffset + kInt32Size; static const int kSourceHashOffset = kVersionHashOffset + kInt32Size;
static const int kCpuFeaturesOffset = kSourceHashOffset + kInt32Size; static const int kCpuFeaturesOffset = kSourceHashOffset + kInt32Size;
static const int kFlagHashOffset = kCpuFeaturesOffset + kInt32Size; static const int kFlagHashOffset = kCpuFeaturesOffset + kInt32Size;
...@@ -111,7 +112,8 @@ class SerializedCodeData : public SerializedData { ...@@ -111,7 +112,8 @@ class SerializedCodeData : public SerializedData {
static const int kPayloadLengthOffset = kNumCodeStubKeysOffset + kInt32Size; static const int kPayloadLengthOffset = kNumCodeStubKeysOffset + kInt32Size;
static const int kChecksum1Offset = kPayloadLengthOffset + kInt32Size; static const int kChecksum1Offset = kPayloadLengthOffset + kInt32Size;
static const int kChecksum2Offset = kChecksum1Offset + kInt32Size; static const int kChecksum2Offset = kChecksum1Offset + kInt32Size;
static const int kHeaderSize = kChecksum2Offset + kInt32Size; static const int kUnalignedHeaderSize = kChecksum2Offset + kInt32Size;
static const int kHeaderSize = POINTER_SIZE_ALIGN(kUnalignedHeaderSize);
// Used when consuming. // Used when consuming.
static const SerializedCodeData FromCachedData( static const SerializedCodeData FromCachedData(
......
...@@ -76,6 +76,10 @@ void Deserializer::Initialize(Isolate* isolate) { ...@@ -76,6 +76,10 @@ void Deserializer::Initialize(Isolate* isolate) {
external_reference_table_ = ExternalReferenceTable::instance(isolate); external_reference_table_ = ExternalReferenceTable::instance(isolate);
CHECK_EQ(magic_number_, CHECK_EQ(magic_number_,
SerializedData::ComputeMagicNumber(external_reference_table_)); SerializedData::ComputeMagicNumber(external_reference_table_));
// The current isolate must have at least as many API-provided external
// references as the to-be-deserialized snapshot expects and refers to.
CHECK_LE(num_extra_references_,
SerializedData::GetExtraReferences(external_reference_table_));
} }
void Deserializer::Deserialize(Isolate* isolate) { void Deserializer::Deserialize(Isolate* isolate) {
......
...@@ -34,6 +34,7 @@ class Deserializer : public SerializerDeserializer { ...@@ -34,6 +34,7 @@ class Deserializer : public SerializerDeserializer {
: isolate_(NULL), : isolate_(NULL),
source_(data->Payload()), source_(data->Payload()),
magic_number_(data->GetMagicNumber()), magic_number_(data->GetMagicNumber()),
num_extra_references_(data->GetExtraReferences()),
next_map_index_(0), next_map_index_(0),
external_reference_table_(NULL), external_reference_table_(NULL),
deserialized_large_objects_(0), deserialized_large_objects_(0),
...@@ -125,6 +126,7 @@ class Deserializer : public SerializerDeserializer { ...@@ -125,6 +126,7 @@ class Deserializer : public SerializerDeserializer {
SnapshotByteSource source_; SnapshotByteSource source_;
uint32_t magic_number_; uint32_t magic_number_;
uint32_t num_extra_references_;
// The address of the next object that will be allocated in each space. // The address of the next object that will be allocated in each space.
// Each space has a number of chunks reserved by the GC, with each chunk // Each space has a number of chunks reserved by the GC, with each chunk
......
...@@ -245,14 +245,26 @@ class SerializedData { ...@@ -245,14 +245,26 @@ class SerializedData {
} }
uint32_t GetMagicNumber() const { return GetHeaderValue(kMagicNumberOffset); } uint32_t GetMagicNumber() const { return GetHeaderValue(kMagicNumberOffset); }
uint32_t GetExtraReferences() const {
return GetHeaderValue(kExtraExternalReferencesOffset);
}
class ChunkSizeBits : public BitField<uint32_t, 0, 31> {}; class ChunkSizeBits : public BitField<uint32_t, 0, 31> {};
class IsLastChunkBits : public BitField<bool, 31, 1> {}; class IsLastChunkBits : public BitField<bool, 31, 1> {};
static uint32_t ComputeMagicNumber(ExternalReferenceTable* table) { static uint32_t ComputeMagicNumber(ExternalReferenceTable* table) {
uint32_t external_refs = table->size(); uint32_t external_refs = table->size() - table->num_api_references();
return 0xC0DE0000 ^ external_refs; return 0xC0DE0000 ^ external_refs;
} }
static uint32_t GetExtraReferences(ExternalReferenceTable* table) {
return table->num_api_references();
}
static const int kMagicNumberOffset = 0;
static const int kExtraExternalReferencesOffset =
kMagicNumberOffset + kInt32Size;
static const int kVersionHashOffset =
kExtraExternalReferencesOffset + kInt32Size;
protected: protected:
void SetHeaderValue(int offset, uint32_t value) { void SetHeaderValue(int offset, uint32_t value) {
...@@ -271,13 +283,15 @@ class SerializedData { ...@@ -271,13 +283,15 @@ class SerializedData {
static uint32_t ComputeMagicNumber(Isolate* isolate) { static uint32_t ComputeMagicNumber(Isolate* isolate) {
return ComputeMagicNumber(ExternalReferenceTable::instance(isolate)); return ComputeMagicNumber(ExternalReferenceTable::instance(isolate));
} }
static uint32_t GetExtraReferences(Isolate* isolate) {
return GetExtraReferences(ExternalReferenceTable::instance(isolate));
}
void SetMagicNumber(Isolate* isolate) { void SetMagicNumber(Isolate* isolate) {
SetHeaderValue(kMagicNumberOffset, ComputeMagicNumber(isolate)); SetHeaderValue(kMagicNumberOffset, ComputeMagicNumber(isolate));
SetHeaderValue(kExtraExternalReferencesOffset, GetExtraReferences(isolate));
} }
static const int kMagicNumberOffset = 0;
byte* data_; byte* data_;
int size_; int size_;
bool owns_data_; bool owns_data_;
......
...@@ -195,7 +195,7 @@ SnapshotData::SnapshotData(const Serializer* serializer) { ...@@ -195,7 +195,7 @@ SnapshotData::SnapshotData(const Serializer* serializer) {
// Set header values. // Set header values.
SetMagicNumber(serializer->isolate()); SetMagicNumber(serializer->isolate());
SetHeaderValue(kCheckSumOffset, Version::Hash()); SetHeaderValue(kVersionHashOffset, Version::Hash());
SetHeaderValue(kNumReservationsOffset, reservations.length()); SetHeaderValue(kNumReservationsOffset, reservations.length());
SetHeaderValue(kPayloadLengthOffset, payload->length()); SetHeaderValue(kPayloadLengthOffset, payload->length());
...@@ -209,7 +209,7 @@ SnapshotData::SnapshotData(const Serializer* serializer) { ...@@ -209,7 +209,7 @@ SnapshotData::SnapshotData(const Serializer* serializer) {
} }
bool SnapshotData::IsSane() { bool SnapshotData::IsSane() {
return GetHeaderValue(kCheckSumOffset) == Version::Hash(); return GetHeaderValue(kVersionHashOffset) == Version::Hash();
} }
Vector<const SerializedData::Reservation> SnapshotData::Reservations() const { Vector<const SerializedData::Reservation> SnapshotData::Reservations() const {
......
...@@ -39,14 +39,14 @@ class SnapshotData : public SerializedData { ...@@ -39,14 +39,14 @@ class SnapshotData : public SerializedData {
bool IsSane(); bool IsSane();
// The data header consists of uint32_t-sized entries: // The data header consists of uint32_t-sized entries:
// [0] magic number and external reference count // [0] magic number and (internal) external reference count
// [1] version hash // [1] API-provided external reference count
// [2] number of reservation size entries // [2] version hash
// [3] payload length // [3] number of reservation size entries
// [4] payload length
// ... reservations // ... reservations
// ... serialized payload // ... serialized payload
static const int kCheckSumOffset = kMagicNumberOffset + kInt32Size; static const int kNumReservationsOffset = kVersionHashOffset + kInt32Size;
static const int kNumReservationsOffset = kCheckSumOffset + kInt32Size;
static const int kPayloadLengthOffset = kNumReservationsOffset + kInt32Size; static const int kPayloadLengthOffset = kNumReservationsOffset + kInt32Size;
static const int kHeaderSize = kPayloadLengthOffset + kInt32Size; static const int kHeaderSize = kPayloadLengthOffset + kInt32Size;
}; };
......
...@@ -237,9 +237,10 @@ class WasmSerializationTest { ...@@ -237,9 +237,10 @@ class WasmSerializationTest {
} }
void InvalidateVersion() { void InvalidateVersion() {
uint32_t* buffer = reinterpret_cast<uint32_t*>( uint32_t* slot = reinterpret_cast<uint32_t*>(
const_cast<uint8_t*>(serialized_bytes_.first)); const_cast<uint8_t*>(serialized_bytes_.first) +
buffer[SerializedCodeData::kVersionHashOffset] = Version::Hash() + 1; SerializedCodeData::kVersionHashOffset);
*slot = Version::Hash() + 1;
} }
void InvalidateWireBytes() { void InvalidateWireBytes() {
...@@ -247,6 +248,13 @@ class WasmSerializationTest { ...@@ -247,6 +248,13 @@ class WasmSerializationTest {
wire_bytes_.second / 2); wire_bytes_.second / 2);
} }
void InvalidateLength() {
uint32_t* slot = reinterpret_cast<uint32_t*>(
const_cast<uint8_t*>(serialized_bytes_.first) +
SerializedCodeData::kPayloadLengthOffset);
*slot = 0xfefefefeu;
}
v8::MaybeLocal<v8::WasmCompiledModule> Deserialize() { v8::MaybeLocal<v8::WasmCompiledModule> Deserialize() {
ErrorThrower thrower(current_isolate(), ""); ErrorThrower thrower(current_isolate(), "");
v8::MaybeLocal<v8::WasmCompiledModule> deserialized = v8::MaybeLocal<v8::WasmCompiledModule> deserialized =
...@@ -406,6 +414,17 @@ TEST(DeserializeNoSerializedData) { ...@@ -406,6 +414,17 @@ TEST(DeserializeNoSerializedData) {
Cleanup(); Cleanup();
} }
TEST(DeserializeInvalidLength) {
WasmSerializationTest test;
{
HandleScope scope(test.current_isolate());
test.InvalidateLength();
test.DeserializeAndRun();
}
Cleanup(test.current_isolate());
Cleanup();
}
TEST(DeserializeWireBytesAndSerializedDataInvalid) { TEST(DeserializeWireBytesAndSerializedDataInvalid) {
WasmSerializationTest test; WasmSerializationTest test;
{ {
......
...@@ -288,8 +288,9 @@ def Main(argv): ...@@ -288,8 +288,9 @@ def Main(argv):
return_code = 0 return_code = 0
for c in configs: for c in configs:
return_code += configs[c].Build() return_code += configs[c].Build()
for c in configs: if return_code == 0:
return_code += configs[c].RunTests() for c in configs:
return_code += configs[c].RunTests()
if return_code == 0: if return_code == 0:
_Call("notify-send 'Done!' 'V8 compilation finished successfully.'", _Call("notify-send 'Done!' 'V8 compilation finished successfully.'",
silent=True) silent=True)
......
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