[sandbox] Access ExternalString ResourceData via bottlenecks

Bug: v8:10391
Change-Id: I4e86394c53d02eab797c2daad2ccfde6acb83bf0
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2151350
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Reviewed-by: Nico Hartmann <nicohartmann@chromium.org>
Cr-Commit-Position: refs/heads/master@{#67619}
This commit is contained in:
Leszek Swirski 2020-05-06 17:45:50 +02:00 committed by Commit Bot
parent 8140856013
commit 4d1f17e4d6
9 changed files with 53 additions and 39 deletions

View File

@ -20,10 +20,10 @@ namespace internal {
using Node = compiler::Node; using Node = compiler::Node;
TNode<IntPtrT> StringBuiltinsAssembler::DirectStringData( TNode<RawPtrT> StringBuiltinsAssembler::DirectStringData(
TNode<String> string, TNode<Word32T> string_instance_type) { TNode<String> string, TNode<Word32T> string_instance_type) {
// Compute the effective offset of the first character. // Compute the effective offset of the first character.
TVARIABLE(IntPtrT, var_data); TVARIABLE(RawPtrT, var_data);
Label if_sequential(this), if_external(this), if_join(this); Label if_sequential(this), if_external(this), if_join(this);
Branch(Word32Equal(Word32And(string_instance_type, Branch(Word32Equal(Word32And(string_instance_type,
Int32Constant(kStringRepresentationMask)), Int32Constant(kStringRepresentationMask)),
@ -32,9 +32,9 @@ TNode<IntPtrT> StringBuiltinsAssembler::DirectStringData(
BIND(&if_sequential); BIND(&if_sequential);
{ {
var_data = IntPtrAdd( var_data = RawPtrAdd(
IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag), ReinterpretCast<RawPtrT>(BitcastTaggedToWord(string)),
BitcastTaggedToWord(string)); IntPtrConstant(SeqOneByteString::kHeaderSize - kHeapObjectTag));
Goto(&if_join); Goto(&if_join);
} }
@ -47,7 +47,7 @@ TNode<IntPtrT> StringBuiltinsAssembler::DirectStringData(
Int32Constant(kUncachedExternalStringMask)), Int32Constant(kUncachedExternalStringMask)),
Int32Constant(kUncachedExternalStringTag))); Int32Constant(kUncachedExternalStringTag)));
var_data = var_data =
LoadObjectField<IntPtrT>(string, ExternalString::kResourceDataOffset); DecodeExternalPointer(LoadExternalStringResourceData(CAST(string)));
Goto(&if_join); Goto(&if_join);
} }
@ -254,8 +254,8 @@ void StringBuiltinsAssembler::StringEqual_Loop(
CSA_ASSERT(this, WordEqual(LoadStringLengthAsWord(rhs), length)); CSA_ASSERT(this, WordEqual(LoadStringLengthAsWord(rhs), length));
// Compute the effective offset of the first character. // Compute the effective offset of the first character.
TNode<IntPtrT> lhs_data = DirectStringData(lhs, lhs_instance_type); TNode<RawPtrT> lhs_data = DirectStringData(lhs, lhs_instance_type);
TNode<IntPtrT> rhs_data = DirectStringData(rhs, rhs_instance_type); TNode<RawPtrT> rhs_data = DirectStringData(rhs, rhs_instance_type);
// Loop over the {lhs} and {rhs} strings to see if they are equal. // Loop over the {lhs} and {rhs} strings to see if they are equal.
TVARIABLE(IntPtrT, var_offset, IntPtrConstant(0)); TVARIABLE(IntPtrT, var_offset, IntPtrConstant(0));

View File

@ -67,7 +67,7 @@ class StringBuiltinsAssembler : public CodeStubAssembler {
TNode<Word32T> rhs_instance_type, MachineType rhs_type, TNode<Word32T> rhs_instance_type, MachineType rhs_type,
TNode<IntPtrT> length, Label* if_equal, TNode<IntPtrT> length, Label* if_equal,
Label* if_not_equal); Label* if_not_equal);
TNode<IntPtrT> DirectStringData(TNode<String> string, TNode<RawPtrT> DirectStringData(TNode<String> string,
TNode<Word32T> string_instance_type); TNode<Word32T> string_instance_type);
void DispatchOnStringEncodings(const TNode<Word32T> lhs_instance_type, void DispatchOnStringEncodings(const TNode<Word32T> lhs_instance_type,

View File

@ -6881,12 +6881,13 @@ TNode<RawPtrT> ToDirectStringAssembler::TryToSequential(
{ {
STATIC_ASSERT(SeqOneByteString::kHeaderSize == STATIC_ASSERT(SeqOneByteString::kHeaderSize ==
SeqTwoByteString::kHeaderSize); SeqTwoByteString::kHeaderSize);
TNode<IntPtrT> result = BitcastTaggedToWord(var_string_.value()); TNode<RawPtrT> result =
ReinterpretCast<RawPtrT>(BitcastTaggedToWord(var_string_.value()));
if (ptr_kind == PTR_TO_DATA) { if (ptr_kind == PTR_TO_DATA) {
result = IntPtrAdd(result, IntPtrConstant(SeqOneByteString::kHeaderSize - result = RawPtrAdd(result, IntPtrConstant(SeqOneByteString::kHeaderSize -
kHeapObjectTag)); kHeapObjectTag));
} }
var_result = ReinterpretCast<RawPtrT>(result); var_result = result;
Goto(&out); Goto(&out);
} }
@ -6896,13 +6897,13 @@ TNode<RawPtrT> ToDirectStringAssembler::TryToSequential(
if_bailout); if_bailout);
TNode<String> string = var_string_.value(); TNode<String> string = var_string_.value();
TNode<IntPtrT> result = TNode<RawPtrT> result =
LoadObjectField<IntPtrT>(string, ExternalString::kResourceDataOffset); DecodeExternalPointer(LoadExternalStringResourceData(CAST(string)));
if (ptr_kind == PTR_TO_STRING) { if (ptr_kind == PTR_TO_STRING) {
result = IntPtrSub(result, IntPtrConstant(SeqOneByteString::kHeaderSize - result = RawPtrSub(result, IntPtrConstant(SeqOneByteString::kHeaderSize -
kHeapObjectTag)); kHeapObjectTag));
} }
var_result = ReinterpretCast<RawPtrT>(result); var_result = result;
Goto(&out); Goto(&out);
} }

View File

@ -691,7 +691,8 @@ FieldAccess AccessBuilder::ForExternalStringResourceData() {
ExternalString::kResourceDataOffset, ExternalString::kResourceDataOffset,
Handle<Name>(), Handle<Name>(),
MaybeHandle<Map>(), MaybeHandle<Map>(),
Type::ExternalPointer(), V8_HEAP_SANDBOX_BOOL ? Type::SandboxedExternalPointer()
: Type::ExternalPointer(),
MachineType::Pointer(), MachineType::Pointer(),
kNoWriteBarrier}; kNoWriteBarrier};
return access; return access;

View File

@ -5,9 +5,9 @@
#ifndef V8_OBJECTS_STRING_INL_H_ #ifndef V8_OBJECTS_STRING_INL_H_
#define V8_OBJECTS_STRING_INL_H_ #define V8_OBJECTS_STRING_INL_H_
#include "src/common/external-pointer-inl.h"
#include "src/common/external-pointer.h" #include "src/common/external-pointer.h"
#include "src/objects/string.h" #include "src/common/globals.h"
#include "src/handles/handles-inl.h" #include "src/handles/handles-inl.h"
#include "src/heap/factory.h" #include "src/heap/factory.h"
#include "src/numbers/conversions-inl.h" #include "src/numbers/conversions-inl.h"
@ -15,6 +15,7 @@
#include "src/objects/name-inl.h" #include "src/objects/name-inl.h"
#include "src/objects/smi-inl.h" #include "src/objects/smi-inl.h"
#include "src/objects/string-table-inl.h" #include "src/objects/string-table-inl.h"
#include "src/objects/string.h"
#include "src/strings/string-hasher-inl.h" #include "src/strings/string-hasher-inl.h"
// Has to be the last include (doesn't have include guards): // Has to be the last include (doesn't have include guards):
@ -613,9 +614,9 @@ void ExternalString::set_address_as_resource(Isolate* isolate,
EncodeExternalPointer(isolate, address); EncodeExternalPointer(isolate, address);
WriteField<ExternalPointer_t>(kResourceOffset, encoded_address); WriteField<ExternalPointer_t>(kResourceOffset, encoded_address);
if (IsExternalOneByteString()) { if (IsExternalOneByteString()) {
ExternalOneByteString::cast(*this).update_data_cache(); ExternalOneByteString::cast(*this).update_data_cache(isolate);
} else { } else {
ExternalTwoByteString::cast(*this).update_data_cache(); ExternalTwoByteString::cast(*this).update_data_cache(isolate);
} }
} }
@ -625,10 +626,11 @@ uint32_t ExternalString::resource_as_uint32() {
return static_cast<uint32_t>(encoded_address); return static_cast<uint32_t>(encoded_address);
} }
void ExternalString::set_uint32_as_resource(uint32_t value) { void ExternalString::set_uint32_as_resource(Isolate* isolate, uint32_t value) {
WriteField<ExternalPointer_t>(kResourceOffset, value); WriteField<ExternalPointer_t>(kResourceOffset, value);
if (is_uncached()) return; if (is_uncached()) return;
WriteField<Address>(kResourceDataOffset, kNullAddress); WriteField<ExternalPointer_t>(kResourceDataOffset,
EncodeExternalPointer(isolate, kNullAddress));
} }
void ExternalString::DisposeResource(Isolate* isolate) { void ExternalString::DisposeResource(Isolate* isolate) {
@ -655,10 +657,11 @@ DEF_GETTER(ExternalOneByteString, resource,
DecodeExternalPointer(isolate, encoded_address)); DecodeExternalPointer(isolate, encoded_address));
} }
void ExternalOneByteString::update_data_cache() { void ExternalOneByteString::update_data_cache(Isolate* isolate) {
if (is_uncached()) return; if (is_uncached()) return;
WriteField<Address>(kResourceDataOffset, const ExternalPointer_t encoded_resource_data = EncodeExternalPointer(
reinterpret_cast<Address>(resource()->data())); isolate, reinterpret_cast<Address>(resource()->data()));
WriteField<ExternalPointer_t>(kResourceDataOffset, encoded_resource_data);
} }
void ExternalOneByteString::SetResource( void ExternalOneByteString::SetResource(
@ -675,7 +678,7 @@ void ExternalOneByteString::set_resource(
const ExternalPointer_t encoded_address = const ExternalPointer_t encoded_address =
EncodeExternalPointer(isolate, reinterpret_cast<Address>(resource)); EncodeExternalPointer(isolate, reinterpret_cast<Address>(resource));
WriteField<ExternalPointer_t>(kResourceOffset, encoded_address); WriteField<ExternalPointer_t>(kResourceOffset, encoded_address);
if (resource != nullptr) update_data_cache(); if (resource != nullptr) update_data_cache(isolate);
} }
const uint8_t* ExternalOneByteString::GetChars() { const uint8_t* ExternalOneByteString::GetChars() {
@ -695,10 +698,11 @@ DEF_GETTER(ExternalTwoByteString, resource,
DecodeExternalPointer(isolate, encoded_address)); DecodeExternalPointer(isolate, encoded_address));
} }
void ExternalTwoByteString::update_data_cache() { void ExternalTwoByteString::update_data_cache(Isolate* isolate) {
if (is_uncached()) return; if (is_uncached()) return;
WriteField<Address>(kResourceDataOffset, const ExternalPointer_t encoded_resource_data = EncodeExternalPointer(
reinterpret_cast<Address>(resource()->data())); isolate, reinterpret_cast<Address>(resource()->data()));
WriteField<ExternalPointer_t>(kResourceDataOffset, encoded_resource_data);
} }
void ExternalTwoByteString::SetResource( void ExternalTwoByteString::SetResource(
@ -715,7 +719,7 @@ void ExternalTwoByteString::set_resource(
const ExternalPointer_t encoded_address = const ExternalPointer_t encoded_address =
EncodeExternalPointer(isolate, reinterpret_cast<Address>(resource)); EncodeExternalPointer(isolate, reinterpret_cast<Address>(resource));
WriteField<ExternalPointer_t>(kResourceOffset, encoded_address); WriteField<ExternalPointer_t>(kResourceOffset, encoded_address);
if (resource != nullptr) update_data_cache(); if (resource != nullptr) update_data_cache(isolate);
} }
const uint16_t* ExternalTwoByteString::GetChars() { return resource()->data(); } const uint16_t* ExternalTwoByteString::GetChars() { return resource()->data(); }

View File

@ -719,7 +719,7 @@ class ExternalString : public String {
DECL_GETTER(resource_as_address, Address) DECL_GETTER(resource_as_address, Address)
inline void set_address_as_resource(Isolate* isolate, Address address); inline void set_address_as_resource(Isolate* isolate, Address address);
inline uint32_t resource_as_uint32(); inline uint32_t resource_as_uint32();
inline void set_uint32_as_resource(uint32_t value); inline void set_uint32_as_resource(Isolate* isolate, uint32_t value);
// Disposes string's resource object if it has not already been disposed. // Disposes string's resource object if it has not already been disposed.
inline void DisposeResource(Isolate* isolate); inline void DisposeResource(Isolate* isolate);
@ -751,7 +751,7 @@ class ExternalOneByteString : public ExternalString {
// The cached pointer is always valid, as the external character array does = // The cached pointer is always valid, as the external character array does =
// not move during lifetime. Deserialization is the only exception, after // not move during lifetime. Deserialization is the only exception, after
// which the pointer cache has to be refreshed. // which the pointer cache has to be refreshed.
inline void update_data_cache(); inline void update_data_cache(Isolate* isolate);
inline const uint8_t* GetChars(); inline const uint8_t* GetChars();
@ -792,7 +792,7 @@ class ExternalTwoByteString : public ExternalString {
// The cached pointer is always valid, as the external character array does = // The cached pointer is always valid, as the external character array does =
// not move during lifetime. Deserialization is the only exception, after // not move during lifetime. Deserialization is the only exception, after
// which the pointer cache has to be refreshed. // which the pointer cache has to be refreshed.
inline void update_data_cache(); inline void update_data_cache(Isolate* isolate);
inline const uint16_t* GetChars(); inline const uint16_t* GetChars();

View File

@ -20,7 +20,7 @@ extern class ConsString extends String {
@generateBodyDescriptor @generateBodyDescriptor
extern class ExternalString extends String { extern class ExternalString extends String {
resource: ExternalPointer; resource: ExternalPointer;
resource_data: RawPtr; resource_data: ExternalPointer;
} }
extern class ExternalOneByteString extends ExternalString {} extern class ExternalOneByteString extends ExternalString {}

View File

@ -413,7 +413,7 @@ void Serializer::ObjectSerializer::SerializeExternalString() {
if (serializer_->external_reference_encoder_.TryEncode(resource).To( if (serializer_->external_reference_encoder_.TryEncode(resource).To(
&reference)) { &reference)) {
DCHECK(reference.is_from_api()); DCHECK(reference.is_from_api());
string.set_uint32_as_resource(reference.index()); string.set_uint32_as_resource(serializer_->isolate(), reference.index());
SerializeObject(); SerializeObject();
string.set_address_as_resource(serializer_->isolate(), resource); string.set_address_as_resource(serializer_->isolate(), resource);
} else { } else {

View File

@ -7,7 +7,8 @@
#include "debug-helper-internal.h" #include "debug-helper-internal.h"
#include "heap-constants.h" #include "heap-constants.h"
#include "include/v8-internal.h" #include "include/v8-internal.h"
#include "src/common/ptr-compr-inl.h" #include "src/common/external-pointer.h"
#include "src/execution/isolate-utils.h"
#include "src/objects/string-inl.h" #include "src/objects/string-inl.h"
#include "src/strings/unicode-inl.h" #include "src/strings/unicode-inl.h"
#include "torque-generated/class-debug-readers-tq.h" #include "torque-generated/class-debug-readers-tq.h"
@ -323,8 +324,15 @@ class ReadStringVisitor : public TqObjectVisitor {
// require knowledge of the embedder. For now, we only read cached external // require knowledge of the embedder. For now, we only read cached external
// strings. // strings.
if (IsExternalStringCached(object)) { if (IsExternalStringCached(object)) {
uintptr_t data_address = reinterpret_cast<uintptr_t>( ExternalPointer_t resource_data =
GetOrFinish(object->GetResourceDataValue(accessor_))); GetOrFinish(object->GetResourceDataValue(accessor_));
#ifdef V8_COMPRESS_POINTERS
uintptr_t data_address = static_cast<uintptr_t>(DecodeExternalPointer(
Isolate::FromRoot(GetIsolateRoot(heap_addresses_.any_heap_pointer)),
resource_data));
#else
uintptr_t data_address = reinterpret_cast<uintptr_t>(resource_data);
#endif // V8_COMPRESS_POINTERS
if (done_) return; if (done_) return;
ReadStringCharacters<TChar>(object, data_address); ReadStringCharacters<TChar>(object, data_address);
} else { } else {