mirror of
https://github.com/zebrajr/node.git
synced 2025-12-06 12:20:27 +01:00
buffer: backport allocUnsafeSlow
This backports the new `Buffer.allocUnsafeSlow()` API for v5. This backport includes the new API, test cases, and docs additions. Already present API and testcases were not changed. PR-URL: https://github.com/nodejs/node/pull/7169 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
This commit is contained in:
parent
27785aeb37
commit
0ca0827b71
|
|
@ -87,25 +87,27 @@ to one of these new APIs.*
|
||||||
containing a *copy* of the provided string.
|
containing a *copy* of the provided string.
|
||||||
* [`Buffer.alloc(size[, fill[, encoding]])`][buffer_alloc] returns a "filled"
|
* [`Buffer.alloc(size[, fill[, encoding]])`][buffer_alloc] returns a "filled"
|
||||||
`Buffer` instance of the specified size. This method can be significantly
|
`Buffer` instance of the specified size. This method can be significantly
|
||||||
slower than [`Buffer.allocUnsafe(size)`][buffer_allocunsafe] but ensures that
|
slower than [`Buffer.allocUnsafe(size)`][buffer_allocunsafe] but ensures
|
||||||
newly created `Buffer` instances never contain old and potentially sensitive
|
that newly created `Buffer` instances never contain old and potentially
|
||||||
data.
|
sensitive data.
|
||||||
* [`Buffer.allocUnsafe(size)`][buffer_allocunsafe] returns a new `Buffer` of
|
* [`Buffer.allocUnsafe(size)`][buffer_allocunsafe] and
|
||||||
the specified `size` whose content *must* be initialized using either
|
[`Buffer.allocUnsafeSlow(size)`][buffer_allocunsafeslow] each return a
|
||||||
[`buf.fill(0)`][] or written to completely.
|
new `Buffer` of the specified `size` whose content *must* be initialized
|
||||||
|
using either [`buf.fill(0)`][] or written to completely.
|
||||||
|
|
||||||
`Buffer` instances returned by `Buffer.allocUnsafe(size)` *may* be allocated
|
`Buffer` instances returned by `Buffer.allocUnsafe(size)` *may* be allocated
|
||||||
off a shared internal memory pool if the `size` is less than or equal to half
|
off a shared internal memory pool if `size` is less than or equal to half
|
||||||
`Buffer.poolSize`.
|
`Buffer.poolSize`. Instances returned by `Buffer.allocUnsafeSlow(size)` *never*
|
||||||
|
use the shared internal memory pool.
|
||||||
|
|
||||||
### What makes `Buffer.allocUnsafe(size)` "unsafe"?
|
### What makes `Buffer.allocUnsafe(size)` and `Buffer.allocUnsafeSlow(size)` "unsafe"?
|
||||||
|
|
||||||
When calling `Buffer.allocUnsafe()`, the segment of allocated memory is
|
When calling `Buffer.allocUnsafe()` (and `Buffer.allocUnsafeSlow()`), the
|
||||||
*uninitialized* (it is not zeroed-out). While this design makes the allocation
|
segment of allocated memory is *uninitialized* (it is not zeroed-out). While
|
||||||
of memory quite fast, the allocated segment of memory might contain old data
|
this design makes the allocation of memory quite fast, the allocated segment of
|
||||||
that is potentially sensitive. Using a `Buffer` created by
|
memory might contain old data that is potentially sensitive. Using a `Buffer`
|
||||||
`Buffer.allocUnsafe(size)` without *completely* overwriting the memory can
|
created by `Buffer.allocUnsafe()` without *completely* overwriting the memory
|
||||||
allow this old data to be leaked when the `Buffer` memory is read.
|
can allow this old data to be leaked when the `Buffer` memory is read.
|
||||||
|
|
||||||
While there are clear performance advantages to using `Buffer.allocUnsafe()`,
|
While there are clear performance advantages to using `Buffer.allocUnsafe()`,
|
||||||
extra care *must* be taken in order to avoid introducing security
|
extra care *must* be taken in order to avoid introducing security
|
||||||
|
|
@ -240,7 +242,8 @@ Additionally, the [`buf.values()`][], [`buf.keys()`][], and
|
||||||
|
|
||||||
Node.js can be started using the `--zero-fill-buffers` command line option to
|
Node.js can be started using the `--zero-fill-buffers` command line option to
|
||||||
force all newly allocated `Buffer` and `SlowBuffer` instances created using
|
force all newly allocated `Buffer` and `SlowBuffer` instances created using
|
||||||
either `new Buffer(size)` and `new SlowBuffer(size)` to be *automatically
|
either `new Buffer(size)`, `Buffer.allocUnsafe(size)`,
|
||||||
|
`Buffer.allocUnsafeSlow(size)` or `new SlowBuffer(size)` to be *automatically
|
||||||
zero-filled* upon creation. Use of this flag *changes the default behavior* of
|
zero-filled* upon creation. Use of this flag *changes the default behavior* of
|
||||||
these methods and *can have a significant impact* on performance. Use of the
|
these methods and *can have a significant impact* on performance. Use of the
|
||||||
`--zero-fill-buffers` option is recommended only when absolutely necessary to
|
`--zero-fill-buffers` option is recommended only when absolutely necessary to
|
||||||
|
|
@ -449,6 +452,52 @@ Buffer pool if `size` is less than or equal to half `Buffer.poolSize`. The
|
||||||
difference is subtle but can be important when an application requires the
|
difference is subtle but can be important when an application requires the
|
||||||
additional performance that `Buffer.allocUnsafe(size)` provides.
|
additional performance that `Buffer.allocUnsafe(size)` provides.
|
||||||
|
|
||||||
|
### Class Method: Buffer.allocUnsafeSlow(size)
|
||||||
|
|
||||||
|
* `size` {Number}
|
||||||
|
|
||||||
|
Allocates a new *non-zero-filled* and non-pooled `Buffer` of `size` bytes. The
|
||||||
|
`size` must be less than or equal to the value of
|
||||||
|
`require('buffer').kMaxLength` (on 64-bit architectures, `kMaxLength` is
|
||||||
|
`(2^31)-1`). Otherwise, a [`RangeError`][] is thrown. If a `size` less than 0
|
||||||
|
is specified, a zero-length `Buffer` will be created.
|
||||||
|
|
||||||
|
The underlying memory for `Buffer` instances created in this way is *not
|
||||||
|
initialized*. The contents of the newly created `Buffer` are unknown and
|
||||||
|
*may contain sensitive data*. Use [`buf.fill(0)`][] to initialize such
|
||||||
|
`Buffer` instances to zeroes.
|
||||||
|
|
||||||
|
When using `Buffer.allocUnsafe()` to allocate new `Buffer` instances,
|
||||||
|
allocations under 4KB are, by default, sliced from a single pre-allocated
|
||||||
|
`Buffer`. This allows applications to avoid the garbage collection overhead of
|
||||||
|
creating many individually allocated Buffers. This approach improves both
|
||||||
|
performance and memory usage by eliminating the need to track and cleanup as
|
||||||
|
many `Persistent` objects.
|
||||||
|
|
||||||
|
However, in the case where a developer may need to retain a small chunk of
|
||||||
|
memory from a pool for an indeterminate amount of time, it may be appropriate
|
||||||
|
to create an un-pooled Buffer instance using `Buffer.allocUnsafeSlow()` then
|
||||||
|
copy out the relevant bits.
|
||||||
|
|
||||||
|
```js
|
||||||
|
// need to keep around a few small chunks of memory
|
||||||
|
const store = [];
|
||||||
|
|
||||||
|
socket.on('readable', () => {
|
||||||
|
const data = socket.read();
|
||||||
|
// allocate for retained data
|
||||||
|
const sb = Buffer.allocUnsafeSlow(10);
|
||||||
|
// copy the data into the new allocation
|
||||||
|
data.copy(sb, 0, 0, 10);
|
||||||
|
store.push(sb);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
Use of `Buffer.allocUnsafeSlow()` should be used only as a last resort *after*
|
||||||
|
a developer has observed undue memory retention in their applications.
|
||||||
|
|
||||||
|
A `TypeError` will be thrown if `size` is not a number.
|
||||||
|
|
||||||
### Class Method: Buffer.byteLength(string[, encoding])
|
### Class Method: Buffer.byteLength(string[, encoding])
|
||||||
|
|
||||||
* `string` {String | Buffer | TypedArray | DataView | ArrayBuffer}
|
* `string` {String | Buffer | TypedArray | DataView | ArrayBuffer}
|
||||||
|
|
@ -1787,7 +1836,8 @@ console.log(buf);
|
||||||
[buffer_from_buffer]: #buffer_class_method_buffer_from_buffer
|
[buffer_from_buffer]: #buffer_class_method_buffer_from_buffer
|
||||||
[buffer_from_arraybuf]: #buffer_class_method_buffer_from_arraybuffer_byteoffset_length
|
[buffer_from_arraybuf]: #buffer_class_method_buffer_from_arraybuffer_byteoffset_length
|
||||||
[buffer_from_string]: #buffer_class_method_buffer_from_str_encoding
|
[buffer_from_string]: #buffer_class_method_buffer_from_str_encoding
|
||||||
[buffer_allocunsafe]: #buffer_class_method_buffer_allocraw_size
|
[buffer_allocunsafe]: #buffer_class_method_buffer_allocunsafe_size
|
||||||
|
[buffer_allocunsafeslow]: #buffer_class_method_buffer_allocunsafeslow_size
|
||||||
[buffer_alloc]: #buffer_class_method_buffer_alloc_size_fill_encoding
|
[buffer_alloc]: #buffer_class_method_buffer_alloc_size_fill_encoding
|
||||||
[`TypedArray.from()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from
|
[`TypedArray.from()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from
|
||||||
[`DataView`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView
|
[`DataView`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,20 @@ Buffer.allocUnsafe = function(size) {
|
||||||
return allocate(size);
|
return allocate(size);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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(size) {
|
||||||
|
if (typeof size !== 'number')
|
||||||
|
throw new TypeError('"size" argument must be a number');
|
||||||
|
return createBuffer(size, true);
|
||||||
|
};
|
||||||
|
|
||||||
|
// If --zero-fill-buffers command line argument is set, a zero-filled
|
||||||
|
// buffer is returned.
|
||||||
|
|
||||||
function SlowBuffer(length) {
|
function SlowBuffer(length) {
|
||||||
if (+length != length)
|
if (+length != length)
|
||||||
length = 0;
|
length = 0;
|
||||||
|
|
|
||||||
|
|
@ -1435,3 +1435,9 @@ assert.equal(SlowBuffer.prototype.offset, undefined);
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
Buffer.from(new ArrayBuffer(0), -1 >>> 0);
|
Buffer.from(new ArrayBuffer(0), -1 >>> 0);
|
||||||
}, /RangeError: 'offset' is out of bounds/);
|
}, /RangeError: 'offset' is out of bounds/);
|
||||||
|
|
||||||
|
// Unpooled buffer (replaces SlowBuffer)
|
||||||
|
const ubuf = Buffer.allocUnsafeSlow(10);
|
||||||
|
assert(ubuf);
|
||||||
|
assert(ubuf.buffer);
|
||||||
|
assert.equal(ubuf.buffer.byteLength, 10);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user