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 {
*/
class V8_EXPORT ValueSerializer {
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);
ValueSerializer(Isolate* isolate, Delegate* delegate);
~ValueSerializer();
/*
......
......@@ -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 ---
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::ValueSerializer serializer;
};
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_; }
......
......@@ -633,7 +633,14 @@ class ErrorUtils : public AllStatic {
T(WasmTrapFuncInvalid, "invalid function") \
T(WasmTrapFuncSigMismatch, "function signature mismatch") \
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 {
public:
......
......@@ -124,8 +124,10 @@ enum class ArrayBufferViewTag : uint8_t {
} // namespace
ValueSerializer::ValueSerializer(Isolate* isolate)
ValueSerializer::ValueSerializer(Isolate* isolate,
v8::ValueSerializer::Delegate* delegate)
: isolate_(isolate),
delegate_(delegate),
zone_(isolate->allocator()),
id_map_(isolate->heap(), &zone_),
array_buffer_transfer_map_(isolate->heap(), &zone_) {}
......@@ -247,9 +249,10 @@ Maybe<bool> ValueSerializer::WriteObject(Handle<Object> object) {
return Just(true);
} else if (object->IsJSReceiver()) {
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) {
// Eliminate callable and exotic objects, which should not be serialized.
InstanceType instance_type = receiver->map()->instance_type();
if (receiver->IsCallable() || instance_type <= LAST_SPECIAL_RECEIVER_TYPE) {
ThrowDataCloneError(MessageTemplate::kDataCloneError, receiver);
return Nothing<bool>();
}
// 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_);
switch (instance_type) {
......@@ -368,8 +372,8 @@ Maybe<bool> ValueSerializer::WriteJSReceiver(Handle<JSReceiver> receiver) {
case JS_DATA_VIEW_TYPE:
return WriteJSArrayBufferView(JSArrayBufferView::cast(*receiver));
default:
UNIMPLEMENTED();
break;
ThrowDataCloneError(MessageTemplate::kDataCloneError, receiver);
return Nothing<bool>();
}
return Nothing<bool>();
}
......@@ -479,6 +483,7 @@ Maybe<bool> ValueSerializer::WriteJSValue(Handle<JSValue> value) {
v8::String::NO_NULL_TERMINATION);
} else {
DCHECK(inner_value->IsSymbol());
ThrowDataCloneError(MessageTemplate::kDataCloneError, value);
return Nothing<bool>();
}
return Just(true);
......@@ -567,10 +572,18 @@ Maybe<bool> ValueSerializer::WriteJSArrayBuffer(JSArrayBuffer* array_buffer) {
return Just(true);
}
if (array_buffer->is_shared()) return Nothing<bool>();
if (array_buffer->was_neutered()) return Nothing<bool>();
if (array_buffer->is_shared()) {
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();
if (byte_length > std::numeric_limits<uint32_t>::max()) {
ThrowDataCloneError(MessageTemplate::kDataCloneError, handle(array_buffer));
return Nothing<bool>();
}
WriteTag(SerializationTag::kArrayBuffer);
......@@ -629,6 +642,24 @@ Maybe<uint32_t> ValueSerializer::WriteJSObjectProperties(
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,
Vector<const uint8_t> data)
: isolate_(isolate),
......@@ -887,7 +918,7 @@ MaybeHandle<String> ValueDeserializer::ReadTwoByteString() {
MaybeHandle<JSObject> ValueDeserializer::ReadJSObject() {
// 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_++;
HandleScope scope(isolate_);
......@@ -910,7 +941,7 @@ MaybeHandle<JSObject> ValueDeserializer::ReadJSObject() {
MaybeHandle<JSArray> ValueDeserializer::ReadSparseJSArray() {
// 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;
if (!ReadVarint<uint32_t>().To(&length)) return MaybeHandle<JSArray>();
......@@ -938,7 +969,7 @@ MaybeHandle<JSArray> ValueDeserializer::ReadSparseJSArray() {
MaybeHandle<JSArray> ValueDeserializer::ReadDenseJSArray() {
// 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;
if (!ReadVarint<uint32_t>().To(&length)) return MaybeHandle<JSArray>();
......@@ -1042,7 +1073,7 @@ MaybeHandle<JSRegExp> ValueDeserializer::ReadJSRegExp() {
MaybeHandle<JSMap> ValueDeserializer::ReadJSMap() {
// 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_);
uint32_t id = next_id_++;
......@@ -1079,7 +1110,7 @@ MaybeHandle<JSMap> ValueDeserializer::ReadJSMap() {
MaybeHandle<JSSet> ValueDeserializer::ReadJSSet() {
// 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_);
uint32_t id = next_id_++;
......
......@@ -12,6 +12,7 @@
#include "src/base/compiler-specific.h"
#include "src/base/macros.h"
#include "src/identity-map.h"
#include "src/messages.h"
#include "src/vector.h"
#include "src/zone.h"
......@@ -41,7 +42,7 @@ enum class SerializationTag : uint8_t;
*/
class ValueSerializer {
public:
explicit ValueSerializer(Isolate* isolate);
ValueSerializer(Isolate* isolate, v8::ValueSerializer::Delegate* delegate);
~ValueSerializer();
/*
......@@ -105,7 +106,16 @@ class ValueSerializer {
Maybe<uint32_t> WriteJSObjectProperties(
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_;
v8::ValueSerializer::Delegate* const delegate_;
std::vector<uint8_t> buffer_;
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