fix: errors thrown in functions over the contextBridge (#28346)

* fix: errors thrown in functions over the contextBridge

* spec: add a test

* fix: ensure exception is a v8::Object
This commit is contained in:
Shelley Vohr 2021-03-30 07:26:49 +00:00 committed by GitHub
parent 9a7cfc42aa
commit 9fecf8369f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 33 additions and 9 deletions

View file

@ -429,21 +429,31 @@ void ProxyFunctionWrapper(const v8::FunctionCallbackInfo<v8::Value>& info) {
v8::MaybeLocal<v8::Value> maybe_return_value; v8::MaybeLocal<v8::Value> maybe_return_value;
bool did_error = false; bool did_error = false;
std::string error_message; v8::Local<v8::Value> error_message;
{ {
v8::TryCatch try_catch(args.isolate()); v8::TryCatch try_catch(args.isolate());
maybe_return_value = func->Call(func_owning_context, func, maybe_return_value = func->Call(func_owning_context, func,
proxied_args.size(), proxied_args.data()); proxied_args.size(), proxied_args.data());
if (try_catch.HasCaught()) { if (try_catch.HasCaught()) {
did_error = true; did_error = true;
auto message = try_catch.Message(); v8::Local<v8::Value> exception = try_catch.Exception();
if (message.IsEmpty() || const char* err_msg =
!gin::ConvertFromV8(args.isolate(), message->Get(), "An unknown exception occurred in the isolated context, an error "
&error_message)) { "occurred but a valid exception was not thrown.";
error_message =
"An unknown exception occurred in the isolated context, an error " if (!exception->IsNull() && exception->IsObject()) {
"occurred but a valid exception was not thrown."; v8::MaybeLocal<v8::Value> maybe_message =
exception.As<v8::Object>()->Get(
func_owning_context,
gin::ConvertToV8(args.isolate(), "message"));
if (!maybe_message.ToLocal(&error_message) ||
!error_message->IsString()) {
error_message = gin::StringToV8(args.isolate(), err_msg);
}
} else {
error_message = gin::StringToV8(args.isolate(), err_msg);
} }
} }
} }
@ -451,7 +461,7 @@ void ProxyFunctionWrapper(const v8::FunctionCallbackInfo<v8::Value>& info) {
if (did_error) { if (did_error) {
v8::Context::Scope calling_context_scope(calling_context); v8::Context::Scope calling_context_scope(calling_context);
args.isolate()->ThrowException( args.isolate()->ThrowException(
v8::Exception::Error(gin::StringToV8(args.isolate(), error_message))); v8::Exception::Error(error_message.As<v8::String>()));
return; return;
} }

View file

@ -364,6 +364,20 @@ describe('contextBridge', () => {
expect(result).equal(true); expect(result).equal(true);
}); });
it('should properly handle errors thrown in proxied functions', async () => {
await makeBindingWindow(() => {
contextBridge.exposeInMainWorld('example', () => { throw new Error('oh no'); });
});
const result = await callWithBindings(async (root: any) => {
try {
root.example();
} catch (e) {
return e.message;
}
});
expect(result).equal('oh no');
});
it('should proxy methods that are callable multiple times', async () => { it('should proxy methods that are callable multiple times', async () => {
await makeBindingWindow(() => { await makeBindingWindow(() => {
contextBridge.exposeInMainWorld('example', { contextBridge.exposeInMainWorld('example', {