[vm] Clear trailing bytes of objects that end up in snapshot images.

Previously, these bytes contained (parts of) the address of null, which is not deterministic.

Bug: https://github.com/dart-lang/sdk/issues/31427
Change-Id: Id3eb16b32d15ff5e0648571a1168dc6f9e3fcbe5
Reviewed-on: https://dart-review.googlesource.com/51181
Reviewed-by: Siva Annamalai <asiva@google.com>
This commit is contained in:
Ryan Macnak 2018-04-16 17:55:51 +00:00
parent 3a5fcf5a87
commit c32e0e4bf3
3 changed files with 105 additions and 34 deletions

View file

@ -1996,23 +1996,13 @@ class RODataSerializationCluster : public SerializationCluster {
objects_.Add(object);
// A string's hash must already be computed when we write it because it
// will be loaded into read-only memory.
if (cid_ == kOneByteStringCid) {
RawOneByteString* str = static_cast<RawOneByteString*>(object);
if (String::GetCachedHash(str) == 0) {
intptr_t hash =
String::Hash(str->ptr()->data(), Smi::Value(str->ptr()->length_));
String::SetCachedHash(str, hash);
}
ASSERT(String::GetCachedHash(str) != 0);
} else if (cid_ == kTwoByteStringCid) {
RawTwoByteString* str = static_cast<RawTwoByteString*>(object);
if (String::GetCachedHash(str) == 0) {
intptr_t hash = String::Hash(str->ptr()->data(),
Smi::Value(str->ptr()->length_) * 2);
String::SetCachedHash(str, hash);
}
ASSERT(String::GetCachedHash(str) != 0);
// will be loaded into read-only memory. Extra bytes due to allocation
// rounding need to be deterministically set for reliable deduplication in
// shared images.
if (object->IsVMHeapObject()) {
// This object is already read-only.
} else {
Object::FinalizeReadOnlyObject(object);
}
}

View file

@ -1038,11 +1038,7 @@ class FinalizeVMIsolateVisitor : public ObjectVisitor {
if (!obj->IsFreeListElement()) {
ASSERT(obj->IsVMHeapObject());
obj->SetMarkBitUnsynchronized();
if (obj->IsStringInstance()) {
RawString* str = reinterpret_cast<RawString*>(obj);
intptr_t hash = String::Hash(str);
String::SetCachedHash(str, hash);
}
Object::FinalizeReadOnlyObject(obj);
#if defined(HASH_IN_OBJECT_HEADER)
// These objects end up in the read-only VM isolate which is shared
// between isolates, so we have to prepopulate them with identity hash
@ -1148,6 +1144,65 @@ void Object::FinalizeVMIsolate(Isolate* isolate) {
}
}
void Object::FinalizeReadOnlyObject(RawObject* object) {
NoSafepointScope no_safepoint;
intptr_t cid = object->GetClassId();
if (cid == kOneByteStringCid) {
RawOneByteString* str = static_cast<RawOneByteString*>(object);
if (String::GetCachedHash(str) == 0) {
intptr_t hash = String::Hash(str);
String::SetCachedHash(str, hash);
}
intptr_t size = OneByteString::UnroundedSize(str);
ASSERT(size <= str->Size());
memset(reinterpret_cast<void*>(RawObject::ToAddr(str) + size), 0,
str->Size() - size);
} else if (cid == kTwoByteStringCid) {
RawTwoByteString* str = static_cast<RawTwoByteString*>(object);
if (String::GetCachedHash(str) == 0) {
intptr_t hash = String::Hash(str);
String::SetCachedHash(str, hash);
}
ASSERT(String::GetCachedHash(str) != 0);
intptr_t size = TwoByteString::UnroundedSize(str);
ASSERT(size <= str->Size());
memset(reinterpret_cast<void*>(RawObject::ToAddr(str) + size), 0,
str->Size() - size);
} else if (cid == kExternalOneByteStringCid) {
RawExternalOneByteString* str =
static_cast<RawExternalOneByteString*>(object);
if (String::GetCachedHash(str) == 0) {
intptr_t hash = String::Hash(str);
String::SetCachedHash(str, hash);
}
} else if (cid == kExternalTwoByteStringCid) {
RawExternalTwoByteString* str =
static_cast<RawExternalTwoByteString*>(object);
if (String::GetCachedHash(str) == 0) {
intptr_t hash = String::Hash(str);
String::SetCachedHash(str, hash);
}
} else if (cid == kCodeSourceMapCid) {
RawCodeSourceMap* map = CodeSourceMap::RawCast(object);
intptr_t size = CodeSourceMap::UnroundedSize(map);
ASSERT(size <= map->Size());
memset(reinterpret_cast<void*>(RawObject::ToAddr(map) + size), 0,
map->Size() - size);
} else if (cid == kStackMapCid) {
RawStackMap* map = StackMap::RawCast(object);
intptr_t size = StackMap::UnroundedSize(map);
ASSERT(size <= map->Size());
memset(reinterpret_cast<void*>(RawObject::ToAddr(map) + size), 0,
map->Size() - size);
} else if (cid == kPcDescriptorsCid) {
RawPcDescriptors* desc = PcDescriptors::RawCast(object);
intptr_t size = PcDescriptors::UnroundedSize(desc);
ASSERT(size <= desc->Size());
memset(reinterpret_cast<void*>(RawObject::ToAddr(desc) + size), 0,
desc->Size() - size);
}
}
void Object::set_vm_isolate_snapshot_object_table(const Array& table) {
ASSERT(Isolate::Current() == Dart::vm_isolate());
*vm_isolate_snapshot_object_table_ = table.raw();

View file

@ -559,6 +559,7 @@ class Object {
static void InitOnce(Isolate* isolate);
static void FinishInitOnce(Isolate* isolate);
static void FinalizeVMIsolate(Isolate* isolate);
static void FinalizeReadOnlyObject(RawObject* object);
// Initialize a new isolate either from a Kernel IR, from source, or from a
// snapshot.
@ -4356,6 +4357,12 @@ class PcDescriptors : public Object {
static const intptr_t kBytesPerElement = 1;
static const intptr_t kMaxElements = kMaxInt32 / kBytesPerElement;
static intptr_t UnroundedSize(RawPcDescriptors* desc) {
return UnroundedSize(desc->ptr()->length_);
}
static intptr_t UnroundedSize(intptr_t len) {
return sizeof(RawPcDescriptors) + len;
}
static intptr_t InstanceSize() {
ASSERT(sizeof(RawPcDescriptors) ==
OFFSET_OF_RETURNED_VALUE(RawPcDescriptors, data));
@ -4363,7 +4370,7 @@ class PcDescriptors : public Object {
}
static intptr_t InstanceSize(intptr_t len) {
ASSERT(0 <= len && len <= kMaxElements);
return RoundedAllocationSize(sizeof(RawPcDescriptors) + len);
return RoundedAllocationSize(UnroundedSize(len));
}
static RawPcDescriptors* New(GrowableArray<uint8_t>* delta_encoded_data);
@ -4478,6 +4485,12 @@ class CodeSourceMap : public Object {
static const intptr_t kBytesPerElement = 1;
static const intptr_t kMaxElements = kMaxInt32 / kBytesPerElement;
static intptr_t UnroundedSize(RawCodeSourceMap* map) {
return UnroundedSize(map->ptr()->length_);
}
static intptr_t UnroundedSize(intptr_t len) {
return sizeof(RawCodeSourceMap) + len;
}
static intptr_t InstanceSize() {
ASSERT(sizeof(RawCodeSourceMap) ==
OFFSET_OF_RETURNED_VALUE(RawCodeSourceMap, data));
@ -4485,7 +4498,7 @@ class CodeSourceMap : public Object {
}
static intptr_t InstanceSize(intptr_t len) {
ASSERT(0 <= len && len <= kMaxElements);
return RoundedAllocationSize(sizeof(RawCodeSourceMap) + len);
return RoundedAllocationSize(UnroundedSize(len));
}
static RawCodeSourceMap* New(intptr_t length);
@ -4544,15 +4557,20 @@ class StackMap : public Object {
static const intptr_t kMaxLengthInBytes = kSmiMax;
static intptr_t UnroundedSize(RawStackMap* map) {
return UnroundedSize(map->ptr()->length_);
}
static intptr_t UnroundedSize(intptr_t len) {
// The stackmap payload is in an array of bytes.
intptr_t payload_size = Utils::RoundUp(len, kBitsPerByte) / kBitsPerByte;
return sizeof(RawStackMap) + payload_size;
}
static intptr_t InstanceSize() {
ASSERT(sizeof(RawStackMap) == OFFSET_OF_RETURNED_VALUE(RawStackMap, data));
return 0;
}
static intptr_t InstanceSize(intptr_t length) {
ASSERT(length >= 0);
// The stackmap payload is in an array of bytes.
intptr_t payload_size = Utils::RoundUp(length, kBitsPerByte) / kBitsPerByte;
return RoundedAllocationSize(sizeof(RawStackMap) + payload_size);
return RoundedAllocationSize(UnroundedSize(length));
}
static RawStackMap* New(intptr_t pc_offset,
BitmapBuilder* bmap,
@ -7377,12 +7395,17 @@ class OneByteString : public AllStatic {
return OFFSET_OF_RETURNED_VALUE(RawOneByteString, data);
}
static intptr_t UnroundedSize(RawOneByteString* str) {
return UnroundedSize(Smi::Value(str->ptr()->length_));
}
static intptr_t UnroundedSize(intptr_t len) {
return sizeof(RawOneByteString) + (len * kBytesPerElement);
}
static intptr_t InstanceSize() {
ASSERT(sizeof(RawOneByteString) ==
OFFSET_OF_RETURNED_VALUE(RawOneByteString, data));
return 0;
}
static intptr_t InstanceSize(intptr_t len) {
ASSERT(sizeof(RawOneByteString) == String::kSizeofRawString);
ASSERT(0 <= len && len <= kMaxElements);
@ -7392,8 +7415,7 @@ class OneByteString : public AllStatic {
// memory allocated for the raw string.
if (len == 0) return InstanceSize(1);
#endif
return String::RoundedAllocationSize(sizeof(RawOneByteString) +
(len * kBytesPerElement));
return String::RoundedAllocationSize(UnroundedSize(len));
}
static RawOneByteString* New(intptr_t len, Heap::Space space);
@ -7521,12 +7543,17 @@ class TwoByteString : public AllStatic {
return OFFSET_OF_RETURNED_VALUE(RawTwoByteString, data);
}
static intptr_t UnroundedSize(RawTwoByteString* str) {
return UnroundedSize(Smi::Value(str->ptr()->length_));
}
static intptr_t UnroundedSize(intptr_t len) {
return sizeof(RawTwoByteString) + (len * kBytesPerElement);
}
static intptr_t InstanceSize() {
ASSERT(sizeof(RawTwoByteString) ==
OFFSET_OF_RETURNED_VALUE(RawTwoByteString, data));
return 0;
}
static intptr_t InstanceSize(intptr_t len) {
ASSERT(sizeof(RawTwoByteString) == String::kSizeofRawString);
ASSERT(0 <= len && len <= kMaxElements);
@ -7534,8 +7561,7 @@ class TwoByteString : public AllStatic {
// If we don't pad, then the external string object does not fit in the
// memory allocated for the raw string.
if (len == 0) return InstanceSize(1);
return String::RoundedAllocationSize(sizeof(RawTwoByteString) +
(len * kBytesPerElement));
return String::RoundedAllocationSize(UnroundedSize(len));
}
static RawTwoByteString* New(intptr_t len, Heap::Space space);