Skip to content

Commit 14e3675

Browse files
Uzlopaktargos
authored andcommitted
errors: improve hideStackFrames
PR-URL: #49990 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent dedfb5a commit 14e3675

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+978
-566
lines changed
+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
'use strict';
2+
3+
const common = require('../common.js');
4+
const assert = require('assert');
5+
6+
const bench = common.createBenchmark(main, {
7+
type: [
8+
'hide-stackframes',
9+
'direct-call',
10+
],
11+
n: [1e7],
12+
}, {
13+
flags: ['--expose-internals'],
14+
});
15+
16+
function main({ n, type }) {
17+
const {
18+
hideStackFrames,
19+
codes: {
20+
ERR_INVALID_ARG_TYPE,
21+
},
22+
} = require('internal/errors');
23+
24+
const testfn = (value) => {
25+
if (typeof value !== 'number') {
26+
throw new ERR_INVALID_ARG_TYPE('Benchmark', 'number', value);
27+
}
28+
};
29+
30+
const hideStackFramesTestfn = hideStackFrames((value) => {
31+
if (typeof value !== 'number') {
32+
throw new ERR_INVALID_ARG_TYPE.HideStackFrameError('Benchmark', 'number', value);
33+
}
34+
});
35+
36+
const fn = type === 'hide-stackframe' ? hideStackFramesTestfn : testfn;
37+
38+
const value = 42;
39+
40+
const length = 1024;
41+
const array = [];
42+
const errCase = false;
43+
44+
for (let i = 0; i < length; ++i) {
45+
array.push(fn(value));
46+
}
47+
48+
bench.start();
49+
50+
for (let i = 0; i < n; i++) {
51+
const index = i % length;
52+
array[index] = fn(value);
53+
}
54+
55+
bench.end(n);
56+
57+
// Verify the entries to prevent dead code elimination from making
58+
// the benchmark invalid.
59+
for (let i = 0; i < length; ++i) {
60+
assert.strictEqual(typeof array[i], errCase ? 'object' : 'undefined');
61+
}
62+
}
+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
'use strict';
2+
3+
const common = require('../common.js');
4+
const assert = require('assert');
5+
6+
const bench = common.createBenchmark(main, {
7+
type: [
8+
'hide-stackframes',
9+
'direct-call',
10+
],
11+
double: ['true', 'false'],
12+
n: [1e5],
13+
}, {
14+
flags: ['--expose-internals'],
15+
});
16+
17+
function main({ n, type, double }) {
18+
const {
19+
hideStackFrames,
20+
codes: {
21+
ERR_INVALID_ARG_TYPE,
22+
},
23+
} = require('internal/errors');
24+
25+
const value = 'err';
26+
27+
const testfn = (value) => {
28+
if (typeof value !== 'number') {
29+
throw new ERR_INVALID_ARG_TYPE('Benchmark', 'number', value);
30+
}
31+
};
32+
33+
const hideStackFramesTestfn = hideStackFrames((value) => {
34+
if (typeof value !== 'number') {
35+
throw new ERR_INVALID_ARG_TYPE.HideStackFrameError('Benchmark', 'number', value);
36+
}
37+
});
38+
39+
function doubleTestfn(value) {
40+
testfn(value);
41+
}
42+
43+
const doubleHideStackFramesTestfn = hideStackFrames((value) => {
44+
hideStackFramesTestfn.withoutStackTrace(value);
45+
});
46+
47+
const fn = type === 'hide-stackframe' ?
48+
double === 'true' ?
49+
doubleHideStackFramesTestfn :
50+
hideStackFramesTestfn :
51+
double === 'true' ?
52+
doubleTestfn :
53+
testfn;
54+
55+
const length = 1024;
56+
const array = [];
57+
let errCase = false;
58+
59+
// Warm up.
60+
for (let i = 0; i < length; ++i) {
61+
try {
62+
fn(value);
63+
} catch (e) {
64+
errCase = true;
65+
array.push(e);
66+
}
67+
}
68+
69+
bench.start();
70+
71+
for (let i = 0; i < n; i++) {
72+
const index = i % length;
73+
try {
74+
fn(value);
75+
} catch (e) {
76+
array[index] = e;
77+
}
78+
}
79+
80+
bench.end(n);
81+
82+
// Verify the entries to prevent dead code elimination from making
83+
// the benchmark invalid.
84+
for (let i = 0; i < length; ++i) {
85+
assert.strictEqual(typeof array[i], errCase ? 'object' : 'undefined');
86+
}
87+
}

benchmark/error/hidestackframes.js

-45
This file was deleted.

lib/.eslintrc.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ rules:
1919
- selector: ThrowStatement > CallExpression[callee.name=/Error$/]
2020
message: Use new keyword when throwing an Error.
2121
# Config specific to lib
22-
- selector: NewExpression[callee.name=/Error$/]:not([callee.name=/^(AssertionError|NghttpError|AbortError)$/])
22+
- selector: NewExpression[callee.name=/Error$/]:not([callee.name=/^(AssertionError|NghttpError|AbortError|NodeAggregateError)$/])
2323
message: Use an error exported by the internal/errors module.
2424
- selector: CallExpression[callee.object.name='Error'][callee.property.name='captureStackTrace']
2525
message: Please use `require('internal/errors').hideStackFrames()` instead.

lib/_http_client.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ const {
7272
traceEnd,
7373
getNextTraceEventId,
7474
} = require('internal/http');
75-
const { connResetException, codes } = require('internal/errors');
75+
const { ConnResetException, codes } = require('internal/errors');
7676
const {
7777
ERR_HTTP_HEADERS_SENT,
7878
ERR_INVALID_ARG_TYPE,
@@ -452,7 +452,7 @@ function socketCloseListener() {
452452
if (res) {
453453
// Socket closed before we emitted 'end' below.
454454
if (!res.complete) {
455-
res.destroy(connResetException('aborted'));
455+
res.destroy(new ConnResetException('aborted'));
456456
}
457457
req._closed = true;
458458
req.emit('close');
@@ -465,7 +465,7 @@ function socketCloseListener() {
465465
// receive a response. The error needs to
466466
// fire on the request.
467467
req.socket._hadError = true;
468-
req.emit('error', connResetException('socket hang up'));
468+
req.emit('error', new ConnResetException('socket hang up'));
469469
}
470470
req._closed = true;
471471
req.emit('close');
@@ -516,7 +516,7 @@ function socketOnEnd() {
516516
// If we don't have a response then we know that the socket
517517
// ended prematurely and we need to emit an error on the request.
518518
req.socket._hadError = true;
519-
req.emit('error', connResetException('socket hang up'));
519+
req.emit('error', new ConnResetException('socket hang up'));
520520
}
521521
if (parser) {
522522
parser.finish();
@@ -869,7 +869,7 @@ function onSocketNT(req, socket, err) {
869869

870870
function _destroy(req, err) {
871871
if (!req.aborted && !err) {
872-
err = connResetException('socket hang up');
872+
err = new ConnResetException('socket hang up');
873873
}
874874
if (err) {
875875
req.emit('error', err);

lib/_http_outgoing.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -663,17 +663,17 @@ function matchHeader(self, state, field, value) {
663663

664664
const validateHeaderName = hideStackFrames((name, label) => {
665665
if (typeof name !== 'string' || !name || !checkIsHttpToken(name)) {
666-
throw new ERR_INVALID_HTTP_TOKEN(label || 'Header name', name);
666+
throw new ERR_INVALID_HTTP_TOKEN.HideStackFramesError(label || 'Header name', name);
667667
}
668668
});
669669

670670
const validateHeaderValue = hideStackFrames((name, value) => {
671671
if (value === undefined) {
672-
throw new ERR_HTTP_INVALID_HEADER_VALUE(value, name);
672+
throw new ERR_HTTP_INVALID_HEADER_VALUE.HideStackFramesError(value, name);
673673
}
674674
if (checkInvalidHeaderChar(value)) {
675675
debug('Header "%s" contains invalid characters', name);
676-
throw new ERR_INVALID_CHAR('header content', name);
676+
throw new ERR_INVALID_CHAR.HideStackFramesError('header content', name);
677677
}
678678
});
679679

lib/_http_server.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ const {
6969
} = require('internal/async_hooks');
7070
const { IncomingMessage } = require('_http_incoming');
7171
const {
72-
connResetException,
72+
ConnResetException,
7373
codes,
7474
} = require('internal/errors');
7575
const {
@@ -790,7 +790,7 @@ function socketOnClose(socket, state) {
790790
function abortIncoming(incoming) {
791791
while (incoming.length) {
792792
const req = incoming.shift();
793-
req.destroy(connResetException('aborted'));
793+
req.destroy(new ConnResetException('aborted'));
794794
}
795795
// Abort socket._httpMessage ?
796796
}

lib/_tls_wrap.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ const { Pipe, constants: PipeConstants } = internalBinding('pipe_wrap');
6666
const { owner_symbol } = require('internal/async_hooks').symbols;
6767
const { isArrayBufferView } = require('internal/util/types');
6868
const { SecureContext: NativeSecureContext } = internalBinding('crypto');
69-
const { connResetException, codes } = require('internal/errors');
69+
const { ConnResetException, codes } = require('internal/errors');
7070
const {
7171
ERR_INVALID_ARG_TYPE,
7272
ERR_INVALID_ARG_VALUE,
@@ -1218,7 +1218,7 @@ function onSocketClose(err) {
12181218
// Emit ECONNRESET
12191219
if (!this._controlReleased && !this[kErrorEmitted]) {
12201220
this[kErrorEmitted] = true;
1221-
const connReset = connResetException('socket hang up');
1221+
const connReset = new ConnResetException('socket hang up');
12221222
this._tlsOptions.server.emit('tlsClientError', connReset, this);
12231223
}
12241224
}
@@ -1724,9 +1724,9 @@ function onConnectEnd() {
17241724
if (!this._hadError) {
17251725
const options = this[kConnectOptions];
17261726
this._hadError = true;
1727-
const error = connResetException('Client network socket disconnected ' +
1728-
'before secure TLS connection was ' +
1729-
'established');
1727+
const error = new ConnResetException('Client network socket disconnected ' +
1728+
'before secure TLS connection was ' +
1729+
'established');
17301730
error.path = options.path;
17311731
error.host = options.host;
17321732
error.port = options.port;

lib/buffer.js

+6-14
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,6 @@ const {
108108
ERR_UNKNOWN_ENCODING,
109109
},
110110
genericNodeError,
111-
hideStackFrames,
112111
} = require('internal/errors');
113112
const {
114113
validateArray,
@@ -386,19 +385,12 @@ Buffer.of = of;
386385

387386
ObjectSetPrototypeOf(Buffer, Uint8Array);
388387

389-
// The 'assertSize' method will remove itself from the callstack when an error
390-
// occurs. This is done simply to keep the internal details of the
391-
// implementation from bleeding out to users.
392-
const assertSize = hideStackFrames((size) => {
393-
validateNumber(size, 'size', 0, kMaxLength);
394-
});
395-
396388
/**
397389
* Creates a new filled Buffer instance.
398390
* alloc(size[, fill[, encoding]])
399391
*/
400392
Buffer.alloc = function alloc(size, fill, encoding) {
401-
assertSize(size);
393+
validateNumber(size, 'size', 0, kMaxLength);
402394
if (fill !== undefined && fill !== 0 && size > 0) {
403395
const buf = createUnsafeBuffer(size);
404396
return _fill(buf, fill, 0, buf.length, encoding);
@@ -411,7 +403,7 @@ Buffer.alloc = function alloc(size, fill, encoding) {
411403
* instance. If `--zero-fill-buffers` is set, will zero-fill the buffer.
412404
*/
413405
Buffer.allocUnsafe = function allocUnsafe(size) {
414-
assertSize(size);
406+
validateNumber(size, 'size', 0, kMaxLength);
415407
return allocate(size);
416408
};
417409

@@ -421,15 +413,15 @@ Buffer.allocUnsafe = function allocUnsafe(size) {
421413
* If `--zero-fill-buffers` is set, will zero-fill the buffer.
422414
*/
423415
Buffer.allocUnsafeSlow = function allocUnsafeSlow(size) {
424-
assertSize(size);
416+
validateNumber(size, 'size', 0, kMaxLength);
425417
return createUnsafeBuffer(size);
426418
};
427419

428420
// If --zero-fill-buffers command line argument is set, a zero-filled
429421
// buffer is returned.
430-
function SlowBuffer(length) {
431-
assertSize(length);
432-
return createUnsafeBuffer(length);
422+
function SlowBuffer(size) {
423+
validateNumber(size, 'size', 0, kMaxLength);
424+
return createUnsafeBuffer(size);
433425
}
434426

435427
ObjectSetPrototypeOf(SlowBuffer.prototype, Uint8ArrayPrototype);

0 commit comments

Comments
 (0)