-
-
Notifications
You must be signed in to change notification settings - Fork 34.4k
Description
Version
24.12.0
Platform
not relevant
Subsystem
lib/buffer
What steps will reproduce the bug?
> const buf = Buffer.from(btoa("hello"), "base64");
undefined
> buf.buffer.transfer();
ArrayBuffer {
[Uint8Contents]: <2f 00 00 00 00 00 00 00 68 65 6c 6c 6f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... 8092 more bytes>,
[byteLength]: 8192
}
>
> Buffer.from(btoa("hello"), "base64");
Uncaught RangeError: "offset" is outside of buffer bounds
at Object.write (node:buffer:698:46)
at fromStringFast (node:buffer:480:22)
at fromString (node:buffer:504:51)
at Buffer.from (node:buffer:310:12) {
code: 'ERR_BUFFER_OUT_OF_BOUNDS'
}
This is the minimal reproduction. In reality this was encountered by two systems that were unaware of each other assuming the following:
- System 1 assumed that
Buffer.fromreturnsUint8Array(subclasses) that after returning are owned by the caller - System 2 assumed that any
Uint8Arraypassed in is owned by it after passing it in
System 2 was detaching the ArrayBuffer because it passed it to the byobRequest.respond() method (which transfers the buffer). In practice this can and will happen more frequently going forward, because there is now a method to detach and transfer arbitrary ArrayBuffers: ArrayBuffer.prototype.transfer().
System 1 was unaware that transfers were going to happen.
How often does it reproduce? Is there a required condition?
Always
What is the expected behavior? Why is that the expected behavior?
The expected behaviour is that Buffer.from should return Uint8Array's that do not break when the underlying buffer of any one other returned Uint8Array is detached (ie, they should not use a pooled AB).
What do you see instead?
An error is thrown on unrelated Buffer.from() calls when the return value of a prior Buffer.from() is detached.
Additional information
A previous mitigation for this was attempted in #32759, but it is not effective anymore as ArrayBuffer.prototype.transfer() does not care about Node internal symbols on the ArrayBuffer pool.