Commit f72351f5 authored by jbroman's avatar jbroman Committed by Commit bot

Throw exceptions for errors in v8::ValueSerializer.

BUG=chromium:148757,chromium:641964

Review-Url: https://codereview.chromium.org/2307603002
Cr-Commit-Position: refs/heads/master@{#39140}
parent 300f4413
...@@ -1671,7 +1671,20 @@ class V8_EXPORT JSON { ...@@ -1671,7 +1671,20 @@ class V8_EXPORT JSON {
*/ */
class V8_EXPORT ValueSerializer { class V8_EXPORT ValueSerializer {
public: public:
class V8_EXPORT Delegate {
public:
virtual ~Delegate() {}
/*
* Handles the case where a DataCloneError would be thrown in the structured
* clone spec. Other V8 embedders may throw some other appropriate exception
* type.
*/
virtual void ThrowDataCloneError(Local<String> message) = 0;
};
explicit ValueSerializer(Isolate* isolate); explicit ValueSerializer(Isolate* isolate);
ValueSerializer(Isolate* isolate, Delegate* delegate);
~ValueSerializer(); ~ValueSerializer();
/* /*
......
...@@ -2836,13 +2836,18 @@ MaybeLocal<String> JSON::Stringify(Local<Context> context, ...@@ -2836,13 +2836,18 @@ MaybeLocal<String> JSON::Stringify(Local<Context> context,
// --- V a l u e S e r i a l i z a t i o n --- // --- V a l u e S e r i a l i z a t i o n ---
struct ValueSerializer::PrivateData { struct ValueSerializer::PrivateData {
explicit PrivateData(i::Isolate* i) : isolate(i), serializer(i) {} explicit PrivateData(i::Isolate* i, ValueSerializer::Delegate* delegate)
: isolate(i), serializer(i, delegate) {}
i::Isolate* isolate; i::Isolate* isolate;
i::ValueSerializer serializer; i::ValueSerializer serializer;
}; };
ValueSerializer::ValueSerializer(Isolate* isolate) ValueSerializer::ValueSerializer(Isolate* isolate)
: private_(new PrivateData(reinterpret_cast<i::Isolate*>(isolate))) {} : ValueSerializer(isolate, nullptr) {}
ValueSerializer::ValueSerializer(Isolate* isolate, Delegate* delegate)
: private_(
new PrivateData(reinterpret_cast<i::Isolate*>(isolate), delegate)) {}
ValueSerializer::~ValueSerializer() { delete private_; } ValueSerializer::~ValueSerializer() { delete private_; }
......
...@@ -633,7 +633,14 @@ class ErrorUtils : public AllStatic { ...@@ -633,7 +633,14 @@ class ErrorUtils : public AllStatic {
T(WasmTrapFuncInvalid, "invalid function") \ T(WasmTrapFuncInvalid, "invalid function") \
T(WasmTrapFuncSigMismatch, "function signature mismatch") \ T(WasmTrapFuncSigMismatch, "function signature mismatch") \
T(WasmTrapInvalidIndex, "invalid index into function table") \ T(WasmTrapInvalidIndex, "invalid index into function table") \
T(WasmTrapTypeError, "invalid type") T(WasmTrapTypeError, "invalid type") \
/* DataCloneError messages */ \
T(DataCloneError, "% could not be cloned.") \
T(DataCloneErrorNeuteredArrayBuffer, \
"An ArrayBuffer is neutered and could not be cloned.") \
T(DataCloneErrorSharedArrayBufferNotTransferred, \
"A SharedArrayBuffer could not be cloned. SharedArrayBuffer must be " \
"transferred.")
class MessageTemplate { class MessageTemplate {
public: public:
......
...@@ -124,8 +124,10 @@ enum class ArrayBufferViewTag : uint8_t { ...@@ -124,8 +124,10 @@ enum class ArrayBufferViewTag : uint8_t {
} // namespace } // namespace
ValueSerializer::ValueSerializer(Isolate* isolate) ValueSerializer::ValueSerializer(Isolate* isolate,
v8::ValueSerializer::Delegate* delegate)
: isolate_(isolate), : isolate_(isolate),
delegate_(delegate),
zone_(isolate->allocator()), zone_(isolate->allocator()),
id_map_(isolate->heap(), &zone_), id_map_(isolate->heap(), &zone_),
array_buffer_transfer_map_(isolate->heap(), &zone_) {} array_buffer_transfer_map_(isolate->heap(), &zone_) {}
...@@ -247,9 +249,10 @@ Maybe<bool> ValueSerializer::WriteObject(Handle<Object> object) { ...@@ -247,9 +249,10 @@ Maybe<bool> ValueSerializer::WriteObject(Handle<Object> object) {
return Just(true); return Just(true);
} else if (object->IsJSReceiver()) { } else if (object->IsJSReceiver()) {
return WriteJSReceiver(Handle<JSReceiver>::cast(object)); return WriteJSReceiver(Handle<JSReceiver>::cast(object));
} else {
ThrowDataCloneError(MessageTemplate::kDataCloneError, object);
return Nothing<bool>();
} }
UNIMPLEMENTED();
return Nothing<bool>();
} }
} }
...@@ -337,11 +340,12 @@ Maybe<bool> ValueSerializer::WriteJSReceiver(Handle<JSReceiver> receiver) { ...@@ -337,11 +340,12 @@ Maybe<bool> ValueSerializer::WriteJSReceiver(Handle<JSReceiver> receiver) {
// Eliminate callable and exotic objects, which should not be serialized. // Eliminate callable and exotic objects, which should not be serialized.
InstanceType instance_type = receiver->map()->instance_type(); InstanceType instance_type = receiver->map()->instance_type();
if (receiver->IsCallable() || instance_type <= LAST_SPECIAL_RECEIVER_TYPE) { if (receiver->IsCallable() || instance_type <= LAST_SPECIAL_RECEIVER_TYPE) {
ThrowDataCloneError(MessageTemplate::kDataCloneError, receiver);
return Nothing<bool>(); return Nothing<bool>();
} }
// If we are at the end of the stack, abort. This function may recurse. // If we are at the end of the stack, abort. This function may recurse.
if (StackLimitCheck(isolate_).HasOverflowed()) return Nothing<bool>(); STACK_CHECK(isolate_, Nothing<bool>());
HandleScope scope(isolate_); HandleScope scope(isolate_);
switch (instance_type) { switch (instance_type) {
...@@ -368,8 +372,8 @@ Maybe<bool> ValueSerializer::WriteJSReceiver(Handle<JSReceiver> receiver) { ...@@ -368,8 +372,8 @@ Maybe<bool> ValueSerializer::WriteJSReceiver(Handle<JSReceiver> receiver) {
case JS_DATA_VIEW_TYPE: case JS_DATA_VIEW_TYPE:
return WriteJSArrayBufferView(JSArrayBufferView::cast(*receiver)); return WriteJSArrayBufferView(JSArrayBufferView::cast(*receiver));
default: default:
UNIMPLEMENTED(); ThrowDataCloneError(MessageTemplate::kDataCloneError, receiver);
break; return Nothing<bool>();
} }
return Nothing<bool>(); return Nothing<bool>();
} }
...@@ -479,6 +483,7 @@ Maybe<bool> ValueSerializer::WriteJSValue(Handle<JSValue> value) { ...@@ -479,6 +483,7 @@ Maybe<bool> ValueSerializer::WriteJSValue(Handle<JSValue> value) {
v8::String::NO_NULL_TERMINATION); v8::String::NO_NULL_TERMINATION);
} else { } else {
DCHECK(inner_value->IsSymbol()); DCHECK(inner_value->IsSymbol());
ThrowDataCloneError(MessageTemplate::kDataCloneError, value);
return Nothing<bool>(); return Nothing<bool>();
} }
return Just(true); return Just(true);
...@@ -567,10 +572,18 @@ Maybe<bool> ValueSerializer::WriteJSArrayBuffer(JSArrayBuffer* array_buffer) { ...@@ -567,10 +572,18 @@ Maybe<bool> ValueSerializer::WriteJSArrayBuffer(JSArrayBuffer* array_buffer) {
return Just(true); return Just(true);
} }
if (array_buffer->is_shared()) return Nothing<bool>(); if (array_buffer->is_shared()) {
if (array_buffer->was_neutered()) return Nothing<bool>(); ThrowDataCloneError(
MessageTemplate::kDataCloneErrorSharedArrayBufferNotTransferred);
return Nothing<bool>();
}
if (array_buffer->was_neutered()) {
ThrowDataCloneError(MessageTemplate::kDataCloneErrorNeuteredArrayBuffer);
return Nothing<bool>();
}
double byte_length = array_buffer->byte_length()->Number(); double byte_length = array_buffer->byte_length()->Number();
if (byte_length > std::numeric_limits<uint32_t>::max()) { if (byte_length > std::numeric_limits<uint32_t>::max()) {
ThrowDataCloneError(MessageTemplate::kDataCloneError, handle(array_buffer));
return Nothing<bool>(); return Nothing<bool>();
} }
WriteTag(SerializationTag::kArrayBuffer); WriteTag(SerializationTag::kArrayBuffer);
...@@ -629,6 +642,24 @@ Maybe<uint32_t> ValueSerializer::WriteJSObjectProperties( ...@@ -629,6 +642,24 @@ Maybe<uint32_t> ValueSerializer::WriteJSObjectProperties(
return Just(properties_written); return Just(properties_written);
} }
void ValueSerializer::ThrowDataCloneError(
MessageTemplate::Template template_index) {
return ThrowDataCloneError(template_index,
isolate_->factory()->empty_string());
}
void ValueSerializer::ThrowDataCloneError(
MessageTemplate::Template template_index, Handle<Object> arg0) {
Handle<String> message =
MessageTemplate::FormatMessage(isolate_, template_index, arg0);
if (delegate_) {
delegate_->ThrowDataCloneError(Utils::ToLocal(message));
} else {
isolate_->Throw(
*isolate_->factory()->NewError(isolate_->error_function(), message));
}
}
ValueDeserializer::ValueDeserializer(Isolate* isolate, ValueDeserializer::ValueDeserializer(Isolate* isolate,
Vector<const uint8_t> data) Vector<const uint8_t> data)
: isolate_(isolate), : isolate_(isolate),
...@@ -887,7 +918,7 @@ MaybeHandle<String> ValueDeserializer::ReadTwoByteString() { ...@@ -887,7 +918,7 @@ MaybeHandle<String> ValueDeserializer::ReadTwoByteString() {
MaybeHandle<JSObject> ValueDeserializer::ReadJSObject() { MaybeHandle<JSObject> ValueDeserializer::ReadJSObject() {
// If we are at the end of the stack, abort. This function may recurse. // If we are at the end of the stack, abort. This function may recurse.
if (StackLimitCheck(isolate_).HasOverflowed()) return MaybeHandle<JSObject>(); STACK_CHECK(isolate_, MaybeHandle<JSObject>());
uint32_t id = next_id_++; uint32_t id = next_id_++;
HandleScope scope(isolate_); HandleScope scope(isolate_);
...@@ -910,7 +941,7 @@ MaybeHandle<JSObject> ValueDeserializer::ReadJSObject() { ...@@ -910,7 +941,7 @@ MaybeHandle<JSObject> ValueDeserializer::ReadJSObject() {
MaybeHandle<JSArray> ValueDeserializer::ReadSparseJSArray() { MaybeHandle<JSArray> ValueDeserializer::ReadSparseJSArray() {
// If we are at the end of the stack, abort. This function may recurse. // If we are at the end of the stack, abort. This function may recurse.
if (StackLimitCheck(isolate_).HasOverflowed()) return MaybeHandle<JSArray>(); STACK_CHECK(isolate_, MaybeHandle<JSArray>());
uint32_t length; uint32_t length;
if (!ReadVarint<uint32_t>().To(&length)) return MaybeHandle<JSArray>(); if (!ReadVarint<uint32_t>().To(&length)) return MaybeHandle<JSArray>();
...@@ -938,7 +969,7 @@ MaybeHandle<JSArray> ValueDeserializer::ReadSparseJSArray() { ...@@ -938,7 +969,7 @@ MaybeHandle<JSArray> ValueDeserializer::ReadSparseJSArray() {
MaybeHandle<JSArray> ValueDeserializer::ReadDenseJSArray() { MaybeHandle<JSArray> ValueDeserializer::ReadDenseJSArray() {
// If we are at the end of the stack, abort. This function may recurse. // If we are at the end of the stack, abort. This function may recurse.
if (StackLimitCheck(isolate_).HasOverflowed()) return MaybeHandle<JSArray>(); STACK_CHECK(isolate_, MaybeHandle<JSArray>());
uint32_t length; uint32_t length;
if (!ReadVarint<uint32_t>().To(&length)) return MaybeHandle<JSArray>(); if (!ReadVarint<uint32_t>().To(&length)) return MaybeHandle<JSArray>();
...@@ -1042,7 +1073,7 @@ MaybeHandle<JSRegExp> ValueDeserializer::ReadJSRegExp() { ...@@ -1042,7 +1073,7 @@ MaybeHandle<JSRegExp> ValueDeserializer::ReadJSRegExp() {
MaybeHandle<JSMap> ValueDeserializer::ReadJSMap() { MaybeHandle<JSMap> ValueDeserializer::ReadJSMap() {
// If we are at the end of the stack, abort. This function may recurse. // If we are at the end of the stack, abort. This function may recurse.
if (StackLimitCheck(isolate_).HasOverflowed()) return MaybeHandle<JSMap>(); STACK_CHECK(isolate_, MaybeHandle<JSMap>());
HandleScope scope(isolate_); HandleScope scope(isolate_);
uint32_t id = next_id_++; uint32_t id = next_id_++;
...@@ -1079,7 +1110,7 @@ MaybeHandle<JSMap> ValueDeserializer::ReadJSMap() { ...@@ -1079,7 +1110,7 @@ MaybeHandle<JSMap> ValueDeserializer::ReadJSMap() {
MaybeHandle<JSSet> ValueDeserializer::ReadJSSet() { MaybeHandle<JSSet> ValueDeserializer::ReadJSSet() {
// If we are at the end of the stack, abort. This function may recurse. // If we are at the end of the stack, abort. This function may recurse.
if (StackLimitCheck(isolate_).HasOverflowed()) return MaybeHandle<JSSet>(); STACK_CHECK(isolate_, MaybeHandle<JSSet>());
HandleScope scope(isolate_); HandleScope scope(isolate_);
uint32_t id = next_id_++; uint32_t id = next_id_++;
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "src/base/compiler-specific.h" #include "src/base/compiler-specific.h"
#include "src/base/macros.h" #include "src/base/macros.h"
#include "src/identity-map.h" #include "src/identity-map.h"
#include "src/messages.h"
#include "src/vector.h" #include "src/vector.h"
#include "src/zone.h" #include "src/zone.h"
...@@ -41,7 +42,7 @@ enum class SerializationTag : uint8_t; ...@@ -41,7 +42,7 @@ enum class SerializationTag : uint8_t;
*/ */
class ValueSerializer { class ValueSerializer {
public: public:
explicit ValueSerializer(Isolate* isolate); ValueSerializer(Isolate* isolate, v8::ValueSerializer::Delegate* delegate);
~ValueSerializer(); ~ValueSerializer();
/* /*
...@@ -105,7 +106,16 @@ class ValueSerializer { ...@@ -105,7 +106,16 @@ class ValueSerializer {
Maybe<uint32_t> WriteJSObjectProperties( Maybe<uint32_t> WriteJSObjectProperties(
Handle<JSObject> object, Handle<FixedArray> keys) WARN_UNUSED_RESULT; Handle<JSObject> object, Handle<FixedArray> keys) WARN_UNUSED_RESULT;
/*
* Asks the delegate to handle an error that occurred during data cloning, by
* throwing an exception appropriate for the host.
*/
void ThrowDataCloneError(MessageTemplate::Template template_index);
V8_NOINLINE void ThrowDataCloneError(MessageTemplate::Template template_index,
Handle<Object> arg0);
Isolate* const isolate_; Isolate* const isolate_;
v8::ValueSerializer::Delegate* const delegate_;
std::vector<uint8_t> buffer_; std::vector<uint8_t> buffer_;
Zone zone_; Zone zone_;
......
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