From c31b6bff3474756a952851fef710a88ce8d5311b Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Sat, 11 Jul 2020 14:19:38 +0200 Subject: [PATCH] worker: fix nested uncaught exception handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are using `ObjectPrototypeToString()` as a cross-context brand check for built-in errors, but weren’t making sure to set that when deserializing errors back into JS objects. Fix that by setting `[Symbol.toStringTag]` manually, to make sure that multiple serialize-and-deserialize cycles keep giving the same result. Fixes: https://github.com/nodejs/node/issues/34309 PR-URL: https://github.com/nodejs/node/pull/34310 Reviewed-By: Luigi Pinca Reviewed-By: Yongsheng Zhang Reviewed-By: Michaël Zasso Reviewed-By: James M Snell --- lib/internal/error-serdes.js | 5 +++++ test/parallel/test-error-serdes.js | 9 +++++++-- test/parallel/test-worker-nested-uncaught.js | 14 ++++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 test/parallel/test-worker-nested-uncaught.js diff --git a/lib/internal/error-serdes.js b/lib/internal/error-serdes.js index 72e8c12e9a7358..5e18448da7046c 100644 --- a/lib/internal/error-serdes.js +++ b/lib/internal/error-serdes.js @@ -14,6 +14,7 @@ const { ObjectKeys, ObjectPrototypeToString, SafeSet, + SymbolToStringTag, } = primordials; const kSerializedError = 0; @@ -116,6 +117,10 @@ function deserializeError(error) { case kSerializedError: const { constructor, properties } = deserialize(error.subarray(1)); const ctor = errors[constructor]; + ObjectDefineProperty(properties, SymbolToStringTag, { + value: { value: 'Error', configurable: true }, + enumerable: true + }); return ObjectCreate(ctor.prototype, properties); case kSerializedObject: return deserialize(error.subarray(1)); diff --git a/test/parallel/test-error-serdes.js b/test/parallel/test-error-serdes.js index 908e81977ba89c..474c4e5b58ddda 100644 --- a/test/parallel/test-error-serdes.js +++ b/test/parallel/test-error-serdes.js @@ -16,12 +16,17 @@ assert.strictEqual(cycle(null), null); assert.strictEqual(cycle(undefined), undefined); assert.strictEqual(cycle('foo'), 'foo'); -{ - const err = cycle(new Error('foo')); +let err = new Error('foo'); +for (let i = 0; i < 10; i++) { assert(err instanceof Error); + assert(Object.prototype.toString.call(err), '[object Error]'); assert.strictEqual(err.name, 'Error'); assert.strictEqual(err.message, 'foo'); assert(/^Error: foo\n/.test(err.stack)); + + const prev = err; + err = cycle(err); + assert.deepStrictEqual(err, prev); } assert.strictEqual(cycle(new RangeError('foo')).name, 'RangeError'); diff --git a/test/parallel/test-worker-nested-uncaught.js b/test/parallel/test-worker-nested-uncaught.js new file mode 100644 index 00000000000000..00bb6832203442 --- /dev/null +++ b/test/parallel/test-worker-nested-uncaught.js @@ -0,0 +1,14 @@ +'use strict'; +const common = require('../common'); +const { Worker } = require('worker_threads'); + +// Regression test for https://github.com/nodejs/node/issues/34309 + +const w = new Worker( + `const { Worker } = require('worker_threads'); + new Worker("throw new Error('uncaught')", { eval:true })`, + { eval: true }); +w.on('error', common.expectsError({ + name: 'Error', + message: 'uncaught' +}));