Skip to content

Commit 71f1340

Browse files
committed
lib: deserialize to native errors in error_serdes
1 parent 8d11399 commit 71f1340

File tree

3 files changed

+50
-11
lines changed

3 files changed

+50
-11
lines changed

lib/internal/error_serdes.js

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const {
66
EvalError,
77
FunctionPrototypeCall,
88
ObjectAssign,
9-
ObjectCreate,
9+
ObjectDefineProperties,
1010
ObjectDefineProperty,
1111
ObjectGetOwnPropertyDescriptor,
1212
ObjectGetOwnPropertyNames,
@@ -15,11 +15,12 @@ const {
1515
ObjectPrototypeToString,
1616
RangeError,
1717
ReferenceError,
18+
ReflectConstruct,
19+
ReflectDeleteProperty,
1820
SafeSet,
1921
StringFromCharCode,
2022
StringPrototypeSubstring,
2123
SymbolFor,
22-
SymbolToStringTag,
2324
SyntaxError,
2425
TypeError,
2526
TypedArrayPrototypeGetBuffer,
@@ -28,6 +29,8 @@ const {
2829
URIError,
2930
} = primordials;
3031

32+
const assert = require('internal/assert');
33+
3134
const { Buffer } = require('buffer');
3235
const { inspect: { custom: customInspectSymbol } } = require('util');
3336

@@ -40,6 +43,7 @@ const kCircularReference = 5;
4043

4144
const kSymbolStringLength = 'Symbol('.length;
4245

46+
// TODO: implement specific logic for AggregateError/SuppressedError
4347
const errors = {
4448
Error, TypeError, RangeError, URIError, SyntaxError, ReferenceError, EvalError,
4549
};
@@ -166,16 +170,17 @@ function deserializeError(error) {
166170
switch (error[0]) {
167171
case kSerializedError: {
168172
const { constructor, properties } = deserialize(error.subarray(1));
169-
const ctor = errors[constructor];
170-
ObjectDefineProperty(properties, SymbolToStringTag, {
171-
__proto__: null,
172-
value: { __proto__: null, value: 'Error', configurable: true },
173-
enumerable: true,
174-
});
173+
assert(errorConstructorNames.has(constructor), 'Invalid constructor');
175174
if ('cause' in properties && 'value' in properties.cause) {
176175
properties.cause.value = deserializeError(properties.cause.value);
177176
}
178-
return ObjectCreate(ctor.prototype, properties);
177+
// Invoke the Error constructor to gain an object with an [[ErrorData]] internal slot
178+
const ret = ReflectConstruct(Error, [], errors[constructor]);
179+
// Delete any properties defined by the Error constructor before assigning from source
180+
ArrayPrototypeForEach(ObjectGetOwnPropertyNames(ret), (key) => {
181+
ReflectDeleteProperty(ret, key);
182+
});
183+
return ObjectDefineProperties(ret, properties);
179184
}
180185
case kSerializedObject:
181186
return deserialize(error.subarray(1));
@@ -196,7 +201,7 @@ function deserializeError(error) {
196201
[customInspectSymbol]: () => '[Circular object]',
197202
};
198203
}
199-
require('assert').fail('This should not happen');
204+
assert.fail('Unknown serializer flag');
200205
}
201206

202207
module.exports = { serializeError, deserializeError };

test/es-module/test-esm-loader-with-syntax-error.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ describe('ESM: loader with syntax error', { concurrency: !process.env.TEST_PARAL
1313
path('print-error-message.js'),
1414
]);
1515

16-
match(stderr, /SyntaxError \[Error\]:/);
16+
match(stderr, /SyntaxError:/);
1717
ok(!stderr.includes('Bad command or file name'));
1818
notStrictEqual(code, 0);
1919
});
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
'use strict';
2+
const common = require('../common');
3+
const assert = require('assert');
4+
const { isNativeError } = require('util/types');
5+
const { Worker } = require('worker_threads');
6+
7+
const validateError = (error, ctor) => {
8+
assert.strictEqual(error.constructor, ctor);
9+
assert.strictEqual(Object.getPrototypeOf(error), ctor.prototype);
10+
assert(isNativeError(error));
11+
};
12+
13+
{
14+
const w = new Worker('throw new Error()', { eval: true });
15+
w.on('error', common.mustCall((error) => {
16+
validateError(error, Error);
17+
}));
18+
}
19+
20+
{
21+
const w = new Worker('throw new RangeError()', { eval: true });
22+
w.on('error', common.mustCall((error) => {
23+
validateError(error, RangeError);
24+
}));
25+
}
26+
27+
{
28+
const w = new Worker('throw new Error(undefined, { cause: new TypeError() })', { eval: true });
29+
w.on('error', common.mustCall((error) => {
30+
validateError(error, Error);
31+
assert.notStrictEqual(error.cause, undefined);
32+
validateError(error.cause, TypeError);
33+
}));
34+
}

0 commit comments

Comments
 (0)