Skip to content

Commit 12e671d

Browse files
stragerzbjornson
authored andcommittedFeb 28, 2021
Fix crash if exception thrown from onload/onerror
If a user-provided .onload or .onerror handler on an Image throws an exception, the Node.js process crashes: FATAL ERROR: v8::ToLocalChecked Empty MaybeLocal. 1: 0x94d778 node::Abort() [node] 2: 0x94edb1 node::OnFatalError(char const*, char const*) [node] 3: 0xad5b0d v8::Utils::ReportApiFailure(char const*, char const*) [node] 4: 0x7f98f47799ae Image::SetSource(Nan::FunctionCallbackInfo<v8::Value> const&) [/home/strager/tmp/Projects/node-canvas/build/Release/canvas.node] 5: 0x7f98f4774fec [/home/strager/tmp/Projects/node-canvas/build/Release/canvas.node] 6: 0xb395b9 v8::internal::FunctionCallbackArguments::Call(v8::internal::CallHandlerInfo) [node] 7: 0xb39970 [node] 8: 0xb3a1ea [node] 9: 0xb3aa99 v8::internal::Builtin_HandleApiCall(int, unsigned long*, v8::internal::Isolate*) [node] 10: 0x12e89b9 [node] Fix this issue by not requiring a return value from the .onload and .onerror functions.
1 parent 8cd191c commit 12e671d

File tree

3 files changed

+25
-2
lines changed

3 files changed

+25
-2
lines changed
 

‎CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ project adheres to [Semantic Versioning](http://semver.org/).
2222
* Fix benchmark for createPNGStream (#1672)
2323
* Fix dangling reference in BackendOperationNotAvailable exception (#1740)
2424
* Fix always-false comparison warning in Canvas.cc.
25+
* Fix Node.js crash when throwing from an onload or onerror handler.
2526

2627
2.7.0
2728
==================

‎src/Image.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -271,14 +271,14 @@ NAN_METHOD(Image::SetSource){
271271
argv[0] = Nan::Error(Nan::New(cairo_status_to_string(status)).ToLocalChecked());
272272
}
273273
Local<Context> ctx = Nan::GetCurrentContext();
274-
Nan::Call(onerrorFn.As<Function>(), ctx->Global(), 1, argv).ToLocalChecked();
274+
Nan::Call(onerrorFn.As<Function>(), ctx->Global(), 1, argv);
275275
}
276276
} else {
277277
img->loaded();
278278
Local<Value> onloadFn = Nan::Get(info.This(), Nan::New("onload").ToLocalChecked()).ToLocalChecked();
279279
if (onloadFn->IsFunction()) {
280280
Local<Context> ctx = Nan::GetCurrentContext();
281-
Nan::Call(onloadFn.As<Function>(), ctx->Global(), 0, NULL).ToLocalChecked();
281+
Nan::Call(onloadFn.As<Function>(), ctx->Global(), 0, NULL);
282282
}
283283
}
284284
}

‎test/image.test.js

+22
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,28 @@ describe('Image', function () {
9595
img.src = Buffer.from('89504E470D', 'hex')
9696
})
9797

98+
it('propagates exceptions thrown by onload', function () {
99+
class MyError extends Error {}
100+
const img = new Image()
101+
img.onload = () => {
102+
throw new MyError()
103+
}
104+
assert.throws(() => {
105+
img.src = jpg_face
106+
}, MyError);
107+
})
108+
109+
it('propagates exceptions thrown by onerror', function () {
110+
class MyError extends Error {}
111+
const img = new Image()
112+
img.onerror = () => {
113+
throw new MyError()
114+
}
115+
assert.throws(() => {
116+
img.src = Buffer.from('', 'hex')
117+
}, MyError);
118+
})
119+
98120
it('loads SVG data URL base64', function () {
99121
if (!HAVE_SVG) this.skip();
100122
const base64Enc = fs.readFileSync(svg_tree, 'base64')

0 commit comments

Comments
 (0)
Please sign in to comment.