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,
internal_isolate->set_array_buffer_allocator(&data->allocator_);
internal_isolate->set_api_external_references(external_references);
isolate->Enter();
if (existing_snapshot) {
internal_isolate->set_snapshot_blob(existing_snapshot);
const StartupData* 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);
} else {
internal_isolate->Init(nullptr);
......
......@@ -46,6 +46,7 @@ ExternalReferenceTable::ExternalReferenceTable(Isolate* isolate) {
AddAccessors(isolate);
AddStubCache(isolate);
AddDeoptEntries(isolate);
// API references must be added last.
AddApiReferences(isolate);
}
......
......@@ -23,6 +23,7 @@ class ExternalReferenceTable {
Address address(uint32_t i) { return refs_[i].address; }
const char* name(uint32_t i) { return refs_[i].name; }
bool is_api_reference(uint32_t i) { return i >= api_refs_start_; }
uint32_t num_api_references() { return size() - api_refs_start_; }
#ifdef DEBUG
void increment_count(uint32_t i) { refs_[i].count++; }
......
......@@ -387,6 +387,9 @@ SerializedCodeData::SerializedCodeData(const List<byte>* payload,
SetHeaderValue(kNumCodeStubKeysOffset, num_stub_keys);
SetHeaderValue(kPayloadLengthOffset, payload->length());
// Zero out any padding in the header.
memset(data_ + kUnalignedHeaderSize, 0, kHeaderSize - kUnalignedHeaderSize);
// Copy reservation chunk sizes.
CopyBytes(data_ + kHeaderSize, reinterpret_cast<byte*>(reservations.begin()),
reservation_size);
......@@ -395,6 +398,7 @@ SerializedCodeData::SerializedCodeData(const List<byte>* payload,
CopyBytes(data_ + kHeaderSize + reservation_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);
// Copy serialized data.
......@@ -411,10 +415,14 @@ SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
if (this->size_ < kHeaderSize) return INVALID_HEADER;
uint32_t magic_number = GetMagicNumber();
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 source_hash = GetHeaderValue(kSourceHashOffset);
uint32_t cpu_features = GetHeaderValue(kCpuFeaturesOffset);
uint32_t flags_hash = GetHeaderValue(kFlagHashOffset);
uint32_t payload_length = GetHeaderValue(kPayloadLengthOffset);
uint32_t c1 = GetHeaderValue(kChecksum1Offset);
uint32_t c2 = GetHeaderValue(kChecksum2Offset);
if (version_hash != Version::Hash()) return VERSION_MISMATCH;
......@@ -423,6 +431,12 @@ SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck(
return CPU_FEATURES_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;
return CHECK_SUCCESS;
}
......
......@@ -85,24 +85,25 @@ class SerializedCodeData : public SerializedData {
CPU_FEATURES_MISMATCH = 4,
FLAGS_MISMATCH = 5,
CHECKSUM_MISMATCH = 6,
INVALID_HEADER = 7
INVALID_HEADER = 7,
LENGTH_MISMATCH = 8
};
// The data header consists of uint32_t-sized entries:
// [0] magic number and external reference count
// [1] version hash
// [2] source hash
// [3] cpu features
// [4] flag hash
// [5] number of code stub keys
// [6] number of reservation size entries
// [7] payload length
// [8] payload checksum part 1
// [9] payload checksum part 2
// [0] magic number and (internally provided) external reference count
// [1] extra (API-provided) external reference count
// [2] version hash
// [3] source hash
// [4] cpu features
// [5] flag hash
// [6] number of code stub keys
// [7] number of reservation size entries
// [8] payload length
// [9] payload checksum part 1
// [10] payload checksum part 2
// ... reservations
// ... code stub keys
// ... serialized payload
static const int kVersionHashOffset = kMagicNumberOffset + kInt32Size;
static const int kSourceHashOffset = kVersionHashOffset + kInt32Size;
static const int kCpuFeaturesOffset = kSourceHashOffset + kInt32Size;
static const int kFlagHashOffset = kCpuFeaturesOffset + kInt32Size;
......@@ -111,7 +112,8 @@ class SerializedCodeData : public SerializedData {
static const int kPayloadLengthOffset = kNumCodeStubKeysOffset + kInt32Size;
static const int kChecksum1Offset = kPayloadLengthOffset + 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.
static const SerializedCodeData FromCachedData(
......
......@@ -76,6 +76,10 @@ void Deserializer::Initialize(Isolate* isolate) {
external_reference_table_ = ExternalReferenceTable::instance(isolate);
CHECK_EQ(magic_number_,
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) {
......
......@@ -34,6 +34,7 @@ class Deserializer : public SerializerDeserializer {
: isolate_(NULL),
source_(data->Payload()),
magic_number_(data->GetMagicNumber()),
num_extra_references_(data->GetExtraReferences()),
next_map_index_(0),
external_reference_table_(NULL),
deserialized_large_objects_(0),
......@@ -125,6 +126,7 @@ class Deserializer : public SerializerDeserializer {
SnapshotByteSource source_;
uint32_t magic_number_;
uint32_t num_extra_references_;
// 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
......
......@@ -245,14 +245,26 @@ class SerializedData {
}
uint32_t GetMagicNumber() const { return GetHeaderValue(kMagicNumberOffset); }
uint32_t GetExtraReferences() const {
return GetHeaderValue(kExtraExternalReferencesOffset);
}
class ChunkSizeBits : public BitField<uint32_t, 0, 31> {};
class IsLastChunkBits : public BitField<bool, 31, 1> {};
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;
}
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:
void SetHeaderValue(int offset, uint32_t value) {
......@@ -271,13 +283,15 @@ class SerializedData {
static uint32_t ComputeMagicNumber(Isolate* isolate) {
return ComputeMagicNumber(ExternalReferenceTable::instance(isolate));
}
static uint32_t GetExtraReferences(Isolate* isolate) {
return GetExtraReferences(ExternalReferenceTable::instance(isolate));
}
void SetMagicNumber(Isolate* isolate) {
SetHeaderValue(kMagicNumberOffset, ComputeMagicNumber(isolate));
SetHeaderValue(kExtraExternalReferencesOffset, GetExtraReferences(isolate));
}
static const int kMagicNumberOffset = 0;
byte* data_;
int size_;
bool owns_data_;
......
......@@ -195,7 +195,7 @@ SnapshotData::SnapshotData(const Serializer* serializer) {
// Set header values.
SetMagicNumber(serializer->isolate());
SetHeaderValue(kCheckSumOffset, Version::Hash());
SetHeaderValue(kVersionHashOffset, Version::Hash());
SetHeaderValue(kNumReservationsOffset, reservations.length());
SetHeaderValue(kPayloadLengthOffset, payload->length());
......@@ -209,7 +209,7 @@ SnapshotData::SnapshotData(const Serializer* serializer) {
}
bool SnapshotData::IsSane() {
return GetHeaderValue(kCheckSumOffset) == Version::Hash();
return GetHeaderValue(kVersionHashOffset) == Version::Hash();
}
Vector<const SerializedData::Reservation> SnapshotData::Reservations() const {
......
......@@ -39,14 +39,14 @@ class SnapshotData : public SerializedData {
bool IsSane();
// The data header consists of uint32_t-sized entries:
// [0] magic number and external reference count
// [1] version hash
// [2] number of reservation size entries
// [3] payload length
// [0] magic number and (internal) external reference count
// [1] API-provided external reference count
// [2] version hash
// [3] number of reservation size entries
// [4] payload length
// ... reservations
// ... serialized payload
static const int kCheckSumOffset = kMagicNumberOffset + kInt32Size;
static const int kNumReservationsOffset = kCheckSumOffset + kInt32Size;
static const int kNumReservationsOffset = kVersionHashOffset + kInt32Size;
static const int kPayloadLengthOffset = kNumReservationsOffset + kInt32Size;
static const int kHeaderSize = kPayloadLengthOffset + kInt32Size;
};
......
......@@ -237,9 +237,10 @@ class WasmSerializationTest {
}
void InvalidateVersion() {
uint32_t* buffer = reinterpret_cast<uint32_t*>(
const_cast<uint8_t*>(serialized_bytes_.first));
buffer[SerializedCodeData::kVersionHashOffset] = Version::Hash() + 1;
uint32_t* slot = reinterpret_cast<uint32_t*>(
const_cast<uint8_t*>(serialized_bytes_.first) +
SerializedCodeData::kVersionHashOffset);
*slot = Version::Hash() + 1;
}
void InvalidateWireBytes() {
......@@ -247,6 +248,13 @@ class WasmSerializationTest {
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() {
ErrorThrower thrower(current_isolate(), "");
v8::MaybeLocal<v8::WasmCompiledModule> deserialized =
......@@ -406,6 +414,17 @@ TEST(DeserializeNoSerializedData) {
Cleanup();
}
TEST(DeserializeInvalidLength) {
WasmSerializationTest test;
{
HandleScope scope(test.current_isolate());
test.InvalidateLength();
test.DeserializeAndRun();
}
Cleanup(test.current_isolate());
Cleanup();
}
TEST(DeserializeWireBytesAndSerializedDataInvalid) {
WasmSerializationTest test;
{
......
......@@ -288,8 +288,9 @@ def Main(argv):
return_code = 0
for c in configs:
return_code += configs[c].Build()
for c in configs:
return_code += configs[c].RunTests()
if return_code == 0:
for c in configs:
return_code += configs[c].RunTests()
if return_code == 0:
_Call("notify-send 'Done!' 'V8 compilation finished successfully.'",
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