diff --git a/benchmark/buffers/buffer-iterate.js b/benchmark/buffers/buffer-iterate.js index 34c7d17b7f2..c1c4f691750 100644 --- a/benchmark/buffers/buffer-iterate.js +++ b/benchmark/buffers/buffer-iterate.js @@ -1,5 +1,5 @@ 'use strict'; -const { Buffer } = require('buffer'); +const SlowBuffer = require('buffer').SlowBuffer; const common = require('../common.js'); const assert = require('assert'); @@ -19,7 +19,7 @@ const methods = { function main({ size, type, method, n }) { const buffer = type === 'fast' ? Buffer.alloc(size) : - Buffer.allocUnsafeSlow(size).fill(0); + SlowBuffer(size).fill(0); const fn = methods[method]; diff --git a/benchmark/buffers/buffer-read-with-byteLength.js b/benchmark/buffers/buffer-read-with-byteLength.js index 4cbe12ef4fe..57e46b8ce44 100644 --- a/benchmark/buffers/buffer-read-with-byteLength.js +++ b/benchmark/buffers/buffer-read-with-byteLength.js @@ -1,6 +1,5 @@ 'use strict'; const common = require('../common.js'); -const { Buffer } = require('buffer'); const types = [ 'IntBE', @@ -19,7 +18,7 @@ const bench = common.createBenchmark(main, { function main({ n, buf, type, byteLength }) { const buff = buf === 'fast' ? Buffer.alloc(8) : - Buffer.allocUnsafeSlow(8); + require('buffer').SlowBuffer(8); const fn = `read${type}`; buff.writeDoubleLE(0, 0); diff --git a/benchmark/buffers/buffer-read.js b/benchmark/buffers/buffer-read.js index 2543db7f5d6..f3b2a564517 100644 --- a/benchmark/buffers/buffer-read.js +++ b/benchmark/buffers/buffer-read.js @@ -1,6 +1,5 @@ 'use strict'; const common = require('../common.js'); -const { Buffer } = require('buffer'); const types = [ 'BigUInt64LE', @@ -28,7 +27,7 @@ const bench = common.createBenchmark(main, { function main({ n, buf, type }) { const buff = buf === 'fast' ? Buffer.alloc(8) : - Buffer.allocUnsafeSlow(8); + require('buffer').SlowBuffer(8); const fn = `read${type}`; buff.writeDoubleLE(0, 0); diff --git a/benchmark/buffers/buffer-slice.js b/benchmark/buffers/buffer-slice.js index e96a31f0b42..cc6e1a8a144 100644 --- a/benchmark/buffers/buffer-slice.js +++ b/benchmark/buffers/buffer-slice.js @@ -1,6 +1,6 @@ 'use strict'; const common = require('../common.js'); -const { Buffer } = require('buffer'); +const SlowBuffer = require('buffer').SlowBuffer; const bench = common.createBenchmark(main, { type: ['fast', 'slow', 'subarray'], @@ -8,7 +8,7 @@ const bench = common.createBenchmark(main, { }); const buf = Buffer.allocUnsafe(1024); -const slowBuf = Buffer.allocUnsafeSlow(1024); +const slowBuf = new SlowBuffer(1024); function main({ n, type }) { const b = type === 'slow' ? slowBuf : buf; diff --git a/benchmark/buffers/buffer-write.js b/benchmark/buffers/buffer-write.js index 25a3a04a130..239abc8a0da 100644 --- a/benchmark/buffers/buffer-write.js +++ b/benchmark/buffers/buffer-write.js @@ -1,6 +1,6 @@ 'use strict'; const common = require('../common.js'); -const { Buffer } = require('buffer'); + const types = [ 'BigUInt64LE', 'BigUInt64BE', @@ -73,7 +73,7 @@ const byteLength = { function main({ n, buf, type }) { const buff = buf === 'fast' ? Buffer.alloc(8) : - Buffer.allocUnsafeSlow(8); + require('buffer').SlowBuffer(8); const fn = `write${type}`; if (!/\d/.test(fn)) diff --git a/doc/api/buffer.md b/doc/api/buffer.md index 66e4aeb8038..d7ba1089a97 100644 --- a/doc/api/buffer.md +++ b/doc/api/buffer.md @@ -5340,6 +5340,28 @@ console.log(newBuf.toString('ascii')); Because the Euro (`€`) sign is not representable in US-ASCII, it is replaced with `?` in the transcoded `Buffer`. +### Class: `SlowBuffer` + + + +> Stability: 0 - Deprecated: Use [`Buffer.allocUnsafeSlow()`][] instead. + +See [`Buffer.allocUnsafeSlow()`][]. This was never a class in the sense that +the constructor always returned a `Buffer` instance, rather than a `SlowBuffer` +instance. + +#### `new SlowBuffer(size)` + + + +* `size` {integer} The desired length of the new `SlowBuffer`. + +See [`Buffer.allocUnsafeSlow()`][]. + ### Buffer constants -Automatically zero-fills all newly allocated [`Buffer`][] instances. +Automatically zero-fills all newly allocated [`Buffer`][] and [`SlowBuffer`][] +instances. ## Environment variables @@ -3895,6 +3896,7 @@ node --stack-trace-limit=12 -p -e "Error.stackTraceLimit" # prints 12 [`ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX`]: errors.md#err_unsupported_typescript_syntax [`NODE_OPTIONS`]: #node_optionsoptions [`NO_COLOR`]: https://no-color.org +[`SlowBuffer`]: buffer.md#class-slowbuffer [`Web Storage`]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API [`WebSocket`]: https://developer.mozilla.org/en-US/docs/Web/API/WebSocket [`YoungGenerationSizeFromSemiSpaceSize`]: https://chromium.googlesource.com/v8/v8.git/+/refs/tags/10.3.129/src/heap/heap.cc#328 diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md index c519bf9e7fd..9217fb2616a 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -695,9 +695,6 @@ Type: End-of-Life -Type: End-of-Life +Type: Runtime -The `SlowBuffer` class has been removed. Please use +The [`SlowBuffer`][] class is deprecated. Please use [`Buffer.allocUnsafeSlow(size)`][] instead. ### DEP0031: `ecdh.setPublicKey()` @@ -3925,6 +3922,7 @@ upon `require('node:module').builtinModules`. [`ReadStream.open()`]: fs.md#class-fsreadstream [`Server.getConnections()`]: net.md#servergetconnectionscallback [`Server.listen({fd: })`]: net.md#serverlistenhandle-backlog-callback +[`SlowBuffer`]: buffer.md#class-slowbuffer [`String.prototype.toWellFormed`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toWellFormed [`WriteStream.open()`]: fs.md#class-fswritestream [`assert`]: assert.md diff --git a/doc/contributing/writing-and-running-benchmarks.md b/doc/contributing/writing-and-running-benchmarks.md index 2664116aefc..1ff494c7c4d 100644 --- a/doc/contributing/writing-and-running-benchmarks.md +++ b/doc/contributing/writing-and-running-benchmarks.md @@ -572,7 +572,7 @@ the code inside the `main` function if it's more than just declaration. ```js 'use strict'; const common = require('../common.js'); -const { Buffer } = require('node:buffer'); +const { SlowBuffer } = require('node:buffer'); const configs = { // Number of operations, specified here so they show up in the report. @@ -603,11 +603,10 @@ function main(conf) { bench.start(); // Do operations here + const BufferConstructor = conf.type === 'fast' ? Buffer : SlowBuffer; for (let i = 0; i < conf.n; i++) { - conf.type === 'fast' ? - Buffer.allocUnsafe(conf.size) : - Buffer.allocUnsafeSlow(conf.size); + new BufferConstructor(conf.size); } // End the timer, pass in the number of operations diff --git a/doc/node.1 b/doc/node.1 index eac925c5fa6..de6a3f7aa5f 100644 --- a/doc/node.1 +++ b/doc/node.1 @@ -619,7 +619,7 @@ If set to 0 then V8 will choose an appropriate size of the thread pool based on If the value provided is larger than V8's maximum, then the largest value will be chosen. . .It Fl -zero-fill-buffers -Automatically zero-fills all newly allocated Buffer instances. +Automatically zero-fills all newly allocated Buffer and SlowBuffer instances. . .It Fl c , Fl -check Check the script's syntax without executing it. diff --git a/lib/buffer.js b/lib/buffer.js index ec3cdd434c2..22bbb95eaf7 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -52,6 +52,7 @@ const { TypedArrayPrototypeSet, TypedArrayPrototypeSlice, Uint8Array, + Uint8ArrayPrototype, } = primordials; const { @@ -88,6 +89,7 @@ const { kIsEncodingSymbol, defineLazyProperties, encodingsMap, + deprecate, } = require('internal/util'); const { isAnyArrayBuffer, @@ -409,15 +411,25 @@ Buffer.allocUnsafe = function allocUnsafe(size) { }; /** - * By default creates a non-zero-filled Buffer instance that is not allocated - * off the pre-initialized pool. If `--zero-fill-buffers` is set, will zero-fill - * the buffer. + * Equivalent to SlowBuffer(num), by default creates a non-zero-filled + * Buffer instance that is not allocated off the pre-initialized pool. + * If `--zero-fill-buffers` is set, will zero-fill the buffer. */ Buffer.allocUnsafeSlow = function allocUnsafeSlow(size) { validateNumber(size, 'size', 0, kMaxLength); return createUnsafeBuffer(size); }; +// If --zero-fill-buffers command line argument is set, a zero-filled +// buffer is returned. +function SlowBuffer(size) { + validateNumber(size, 'size', 0, kMaxLength); + return createUnsafeBuffer(size); +} + +ObjectSetPrototypeOf(SlowBuffer.prototype, Uint8ArrayPrototype); +ObjectSetPrototypeOf(SlowBuffer, Uint8Array); + function allocate(size) { if (size <= 0) { return new FastBuffer(); @@ -1319,6 +1331,10 @@ function isAscii(input) { module.exports = { Buffer, + SlowBuffer: deprecate( + SlowBuffer, + 'SlowBuffer() is deprecated. Please use Buffer.allocUnsafeSlow()', + 'DEP0030'), transcode, isUtf8, isAscii, diff --git a/src/node_options.cc b/src/node_options.cc index f4d5170a629..c0a3384735c 100644 --- a/src/node_options.cc +++ b/src/node_options.cc @@ -1052,7 +1052,8 @@ PerProcessOptionsParser::PerProcessOptionsParser( &PerProcessOptions::v8_thread_pool_size, kAllowedInEnvvar); AddOption("--zero-fill-buffers", - "automatically zero-fill all newly allocated Buffer instances", + "automatically zero-fill all newly allocated Buffer and " + "SlowBuffer instances", &PerProcessOptions::zero_fill_all_buffers, kAllowedInEnvvar); AddOption("--debug-arraybuffer-allocations", diff --git a/test/parallel/test-buffer-alloc.js b/test/parallel/test-buffer-alloc.js index 382cfbc93a6..aad9c6bcab6 100644 --- a/test/parallel/test-buffer-alloc.js +++ b/test/parallel/test-buffer-alloc.js @@ -5,7 +5,7 @@ const assert = require('assert'); const vm = require('vm'); const { - Buffer, + SlowBuffer, kMaxLength, } = require('buffer'); @@ -1104,6 +1104,9 @@ assert.throws(() => Buffer.from(null), { // Test prototype getters don't throw assert.strictEqual(Buffer.prototype.parent, undefined); assert.strictEqual(Buffer.prototype.offset, undefined); +assert.strictEqual(SlowBuffer.prototype.parent, undefined); +assert.strictEqual(SlowBuffer.prototype.offset, undefined); + { // Test that large negative Buffer length inputs don't affect the pool offset. @@ -1136,7 +1139,7 @@ assert.throws(() => { a.copy(b, 0, 0x100000000, 0x100000001); }, outOfRangeError); -// Unpooled buffer +// Unpooled buffer (replaces SlowBuffer) { const ubuf = Buffer.allocUnsafeSlow(10); assert(ubuf); diff --git a/test/parallel/test-buffer-bytelength.js b/test/parallel/test-buffer-bytelength.js index 1013469181f..95d54d425bc 100644 --- a/test/parallel/test-buffer-bytelength.js +++ b/test/parallel/test-buffer-bytelength.js @@ -2,7 +2,7 @@ const common = require('../common'); const assert = require('assert'); -const { Buffer } = require('buffer'); +const SlowBuffer = require('buffer').SlowBuffer; const vm = require('vm'); [ @@ -24,6 +24,7 @@ const vm = require('vm'); }); assert(ArrayBuffer.isView(new Buffer(10))); +assert(ArrayBuffer.isView(new SlowBuffer(10))); assert(ArrayBuffer.isView(Buffer.alloc(10))); assert(ArrayBuffer.isView(Buffer.allocUnsafe(10))); assert(ArrayBuffer.isView(Buffer.allocUnsafeSlow(10))); diff --git a/test/parallel/test-buffer-failed-alloc-typed-arrays.js b/test/parallel/test-buffer-failed-alloc-typed-arrays.js index ac519d2bf7a..699475ad0a8 100644 --- a/test/parallel/test-buffer-failed-alloc-typed-arrays.js +++ b/test/parallel/test-buffer-failed-alloc-typed-arrays.js @@ -2,7 +2,7 @@ require('../common'); const assert = require('assert'); -const { Buffer } = require('buffer'); +const SlowBuffer = require('buffer').SlowBuffer; // Test failed or zero-sized Buffer allocations not affecting typed arrays. // This test exists because of a regression that occurred. Because Buffer @@ -15,6 +15,7 @@ const zeroArray = new Uint32Array(10).fill(0); const sizes = [1e20, 0, 0.1, -1, 'a', undefined, null, NaN]; const allocators = [ Buffer, + SlowBuffer, Buffer.alloc, Buffer.allocUnsafe, Buffer.allocUnsafeSlow, diff --git a/test/parallel/test-buffer-inspect.js b/test/parallel/test-buffer-inspect.js index 0dd15e5a97d..1e8212e8763 100644 --- a/test/parallel/test-buffer-inspect.js +++ b/test/parallel/test-buffer-inspect.js @@ -30,7 +30,7 @@ buffer.INSPECT_MAX_BYTES = 2; let b = Buffer.allocUnsafe(4); b.fill('1234'); -let s = Buffer.allocUnsafeSlow(4); +let s = buffer.SlowBuffer(4); s.fill('1234'); let expected = ''; @@ -41,7 +41,7 @@ assert.strictEqual(util.inspect(s), expected); b = Buffer.allocUnsafe(2); b.fill('12'); -s = Buffer.allocUnsafeSlow(2); +s = buffer.SlowBuffer(2); s.fill('12'); expected = ''; diff --git a/test/parallel/test-buffer-no-negative-allocation.js b/test/parallel/test-buffer-no-negative-allocation.js index e48d9c75457..055e2d5dc69 100644 --- a/test/parallel/test-buffer-no-negative-allocation.js +++ b/test/parallel/test-buffer-no-negative-allocation.js @@ -2,6 +2,7 @@ require('../common'); const assert = require('assert'); +const { SlowBuffer } = require('buffer'); const msg = { code: 'ERR_OUT_OF_RANGE', @@ -29,3 +30,8 @@ assert.throws(() => Buffer.allocUnsafeSlow(-Buffer.poolSize), msg); assert.throws(() => Buffer.allocUnsafeSlow(-100), msg); assert.throws(() => Buffer.allocUnsafeSlow(-1), msg); assert.throws(() => Buffer.allocUnsafeSlow(NaN), msg); + +assert.throws(() => SlowBuffer(-Buffer.poolSize), msg); +assert.throws(() => SlowBuffer(-100), msg); +assert.throws(() => SlowBuffer(-1), msg); +assert.throws(() => SlowBuffer(NaN), msg); diff --git a/test/parallel/test-buffer-over-max-length.js b/test/parallel/test-buffer-over-max-length.js index 5ee07b14d2a..f29d6b62d4a 100644 --- a/test/parallel/test-buffer-over-max-length.js +++ b/test/parallel/test-buffer-over-max-length.js @@ -4,6 +4,7 @@ require('../common'); const assert = require('assert'); const buffer = require('buffer'); +const SlowBuffer = buffer.SlowBuffer; const kMaxLength = buffer.kMaxLength; const bufferMaxSizeMsg = { @@ -12,6 +13,7 @@ const bufferMaxSizeMsg = { }; assert.throws(() => Buffer(kMaxLength + 1), bufferMaxSizeMsg); +assert.throws(() => SlowBuffer(kMaxLength + 1), bufferMaxSizeMsg); assert.throws(() => Buffer.alloc(kMaxLength + 1), bufferMaxSizeMsg); assert.throws(() => Buffer.allocUnsafe(kMaxLength + 1), bufferMaxSizeMsg); assert.throws(() => Buffer.allocUnsafeSlow(kMaxLength + 1), bufferMaxSizeMsg); diff --git a/test/parallel/test-buffer-slow.js b/test/parallel/test-buffer-slow.js index bf104abf4fb..0d89491cfbd 100644 --- a/test/parallel/test-buffer-slow.js +++ b/test/parallel/test-buffer-slow.js @@ -1,13 +1,20 @@ 'use strict'; -require('../common'); +const common = require('../common'); const assert = require('assert'); -const { Buffer, kMaxLength } = require('buffer'); +const buffer = require('buffer'); +const SlowBuffer = buffer.SlowBuffer; const ones = [1, 1, 1, 1]; +common.expectWarning( + 'DeprecationWarning', + 'SlowBuffer() is deprecated. Please use Buffer.allocUnsafeSlow()', + 'DEP0030' +); + // Should create a Buffer -let sb = Buffer.allocUnsafeSlow(4); +let sb = SlowBuffer(4); assert(sb instanceof Buffer); assert.strictEqual(sb.length, 4); sb.fill(1); @@ -19,7 +26,7 @@ for (const [key, value] of sb.entries()) { assert.strictEqual(sb.buffer.byteLength, 4); // Should work without new -sb = Buffer.allocUnsafeSlow(4); +sb = SlowBuffer(4); assert(sb instanceof Buffer); assert.strictEqual(sb.length, 4); sb.fill(1); @@ -28,7 +35,7 @@ for (const [key, value] of sb.entries()) { } // Should work with edge cases -assert.strictEqual(Buffer.allocUnsafeSlow(0).length, 0); +assert.strictEqual(SlowBuffer(0).length, 0); // Should throw with invalid length type const bufferInvalidTypeMsg = { @@ -36,17 +43,17 @@ const bufferInvalidTypeMsg = { name: 'TypeError', message: /^The "size" argument must be of type number/, }; -assert.throws(() => Buffer.allocUnsafeSlow(), bufferInvalidTypeMsg); -assert.throws(() => Buffer.allocUnsafeSlow({}), bufferInvalidTypeMsg); -assert.throws(() => Buffer.allocUnsafeSlow('6'), bufferInvalidTypeMsg); -assert.throws(() => Buffer.allocUnsafeSlow(true), bufferInvalidTypeMsg); +assert.throws(() => SlowBuffer(), bufferInvalidTypeMsg); +assert.throws(() => SlowBuffer({}), bufferInvalidTypeMsg); +assert.throws(() => SlowBuffer('6'), bufferInvalidTypeMsg); +assert.throws(() => SlowBuffer(true), bufferInvalidTypeMsg); // Should throw with invalid length value const bufferMaxSizeMsg = { code: 'ERR_OUT_OF_RANGE', name: 'RangeError', }; -assert.throws(() => Buffer.allocUnsafeSlow(NaN), bufferMaxSizeMsg); -assert.throws(() => Buffer.allocUnsafeSlow(Infinity), bufferMaxSizeMsg); -assert.throws(() => Buffer.allocUnsafeSlow(-1), bufferMaxSizeMsg); -assert.throws(() => Buffer.allocUnsafeSlow(kMaxLength + 1), bufferMaxSizeMsg); +assert.throws(() => SlowBuffer(NaN), bufferMaxSizeMsg); +assert.throws(() => SlowBuffer(Infinity), bufferMaxSizeMsg); +assert.throws(() => SlowBuffer(-1), bufferMaxSizeMsg); +assert.throws(() => SlowBuffer(buffer.kMaxLength + 1), bufferMaxSizeMsg); diff --git a/test/parallel/test-buffer-tostring-rangeerror.js b/test/parallel/test-buffer-tostring-rangeerror.js index a5591213cf2..2c609426354 100644 --- a/test/parallel/test-buffer-tostring-rangeerror.js +++ b/test/parallel/test-buffer-tostring-rangeerror.js @@ -12,7 +12,7 @@ if (!common.enoughTestMem) { const assert = require('assert'); const { - Buffer, + SlowBuffer, constants: { MAX_STRING_LENGTH, }, @@ -24,7 +24,7 @@ const message = { name: 'Error', }; assert.throws(() => Buffer(len).toString('utf8'), message); -assert.throws(() => Buffer.allocUnsafeSlow(len).toString('utf8'), message); +assert.throws(() => SlowBuffer(len).toString('utf8'), message); assert.throws(() => Buffer.alloc(len).toString('utf8'), message); assert.throws(() => Buffer.allocUnsafe(len).toString('utf8'), message); assert.throws(() => Buffer.allocUnsafeSlow(len).toString('utf8'), message); diff --git a/test/parallel/test-buffer-zero-fill-cli.js b/test/parallel/test-buffer-zero-fill-cli.js index 663911b7188..4299f81039b 100644 --- a/test/parallel/test-buffer-zero-fill-cli.js +++ b/test/parallel/test-buffer-zero-fill-cli.js @@ -1,11 +1,11 @@ 'use strict'; // Flags: --zero-fill-buffers -// when using --zero-fill-buffers, every Buffer +// when using --zero-fill-buffers, every Buffer and SlowBuffer // instance must be zero filled upon creation require('../common'); -const { Buffer } = require('buffer'); +const SlowBuffer = require('buffer').SlowBuffer; const assert = require('assert'); function isZeroFilled(buf) { @@ -22,8 +22,9 @@ for (let i = 0; i < 50; i++) { const bufs = [ Buffer.alloc(20), Buffer.allocUnsafe(20), - Buffer.allocUnsafeSlow(20), + SlowBuffer(20), Buffer(20), + new SlowBuffer(20), ]; for (const buf of bufs) { assert(isZeroFilled(buf)); diff --git a/test/parallel/test-icu-transcode.js b/test/parallel/test-icu-transcode.js index 875d954b6ca..e9aced128ee 100644 --- a/test/parallel/test-icu-transcode.js +++ b/test/parallel/test-icu-transcode.js @@ -86,5 +86,5 @@ assert.deepStrictEqual( // Test that it doesn't crash { - buffer.transcode(new buffer.Buffer.allocUnsafeSlow(1), 'utf16le', 'ucs2'); + buffer.transcode(new buffer.SlowBuffer(1), 'utf16le', 'ucs2'); } diff --git a/test/pummel/test-buffer-large-size-slowbuffer.js b/test/pummel/test-buffer-large-size-slowbuffer.js index b4670b41730..5ac058fb276 100644 --- a/test/pummel/test-buffer-large-size-slowbuffer.js +++ b/test/pummel/test-buffer-large-size-slowbuffer.js @@ -5,18 +5,18 @@ const common = require('../common'); common.skipIf32Bits(); const assert = require('node:assert'); -const { Buffer } = require('node:buffer'); +const { + SlowBuffer, +} = require('node:buffer'); const size = 2 ** 31; -// Test slow Buffer with size larger than integer range +// Test SlowBuffer with size larger than integer range try { - assert.throws(() => Buffer.allocUnsafeSlow(size).toString('utf8'), { - code: 'ERR_STRING_TOO_LONG', - }); + assert.throws(() => SlowBuffer(size).toString('utf8'), { code: 'ERR_STRING_TOO_LONG' }); } catch (e) { if (e.code !== 'ERR_MEMORY_ALLOCATION_FAILED') { throw e; } - common.skip('insufficient space for slow Buffer allocation'); + common.skip('insufficient space for SlowBuffer'); }