Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit e9a3426

Browse filesBrowse files
nbbeekenaduh95
authored andcommitted
buffer: make methods work on Uint8Array instances
Removes the reliance on prototype bound methods internally so that Uint8Arrays can be set as the bound `this` value when calling the various Buffer methods. Introduces some additional tamper protection by removing internal reliance on writable properties. Fixes: #56577 PR-URL: #56578 Reviewed-By: Anna Henningsen <anna@addaleax.net>
1 parent 8dd379d commit e9a3426
Copy full SHA for e9a3426

8 files changed

+1,337-156Lines changed: 1337 additions & 156 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎doc/api/buffer.md‎

Copy file name to clipboardExpand all lines: doc/api/buffer.md
+41Lines changed: 41 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,21 @@ function:
415415
* [`Buffer.from(arrayBuffer[, byteOffset[, length]])`][`Buffer.from(arrayBuf)`]
416416
* [`Buffer.from(string[, encoding])`][`Buffer.from(string)`]
417417

418+
### Buffer methods are callable with `Uint8Array` instances
419+
420+
All methods on the Buffer prototype are callable with a `Uint8Array` instance.
421+
422+
```js
423+
const { toString, write } = Buffer.prototype;
424+
425+
const uint8array = new Uint8Array(5);
426+
427+
write.call(uint8array, 'hello', 0, 5, 'utf8'); // 5
428+
// <Uint8Array 68 65 6c 6c 6f>
429+
430+
toString.call(uint8array, 'utf8'); // 'hello'
431+
```
432+
418433
## Buffers and iteration
419434

420435
`Buffer` instances can be iterated over using `for..of` syntax:
@@ -2058,6 +2073,10 @@ console.log(buf.fill('zz', 'hex'));
20582073

20592074
<!-- YAML
20602075
added: v5.3.0
2076+
changes:
2077+
- version: REPLACEME
2078+
pr-url: https://github.com/nodejs/node/pull/56578
2079+
description: supports Uint8Array as `this` value.
20612080
-->
20622081

20632082
* `value` {string|Buffer|Uint8Array|integer} What to search for.
@@ -2945,10 +2964,14 @@ console.log(buf.readInt32LE(1));
29452964
<!-- YAML
29462965
added: v0.11.15
29472966
changes:
2967+
- version: REPLACEME
2968+
pr-url: https://github.com/nodejs/node/pull/56578
2969+
description: supports Uint8Array as `this` value.
29482970
- version: v10.0.0
29492971
pr-url: https://github.com/nodejs/node/pull/18395
29502972
description: Removed `noAssert` and no implicit coercion of the offset
29512973
and `byteLength` to `uint32` anymore.
2974+
29522975
-->
29532976

29542977
* `offset` {integer} Number of bytes to skip before starting to read. Must
@@ -2992,10 +3015,14 @@ console.log(buf.readIntBE(1, 0).toString(16));
29923015
<!-- YAML
29933016
added: v0.11.15
29943017
changes:
3018+
- version: REPLACEME
3019+
pr-url: https://github.com/nodejs/node/pull/56578
3020+
description: supports Uint8Array as `this` value.
29953021
- version: v10.0.0
29963022
pr-url: https://github.com/nodejs/node/pull/18395
29973023
description: Removed `noAssert` and no implicit coercion of the offset
29983024
and `byteLength` to `uint32` anymore.
3025+
29993026
-->
30003027

30013028
* `offset` {integer} Number of bytes to skip before starting to read. Must
@@ -3269,6 +3296,9 @@ console.log(buf.readUInt32LE(1).toString(16));
32693296
<!-- YAML
32703297
added: v0.11.15
32713298
changes:
3299+
- version: REPLACEME
3300+
pr-url: https://github.com/nodejs/node/pull/56578
3301+
description: supports Uint8Array as `this` value.
32723302
- version:
32733303
- v14.9.0
32743304
- v12.19.0
@@ -3319,6 +3349,9 @@ console.log(buf.readUIntBE(1, 6).toString(16));
33193349
<!-- YAML
33203350
added: v0.11.15
33213351
changes:
3352+
- version: REPLACEME
3353+
pr-url: https://github.com/nodejs/node/pull/56578
3354+
description: supports Uint8Array as `this` value.
33223355
- version:
33233356
- v14.9.0
33243357
- v12.19.0
@@ -3771,6 +3804,10 @@ console.log(copy);
37713804

37723805
<!-- YAML
37733806
added: v0.1.90
3807+
changes:
3808+
- version: REPLACEME
3809+
pr-url: https://github.com/nodejs/node/pull/56578
3810+
description: supports Uint8Array as `this` value.
37743811
-->
37753812

37763813
* `encoding` {string} The character encoding to use. **Default:** `'utf8'`.
@@ -3909,6 +3946,10 @@ for (const value of buf) {
39093946

39103947
<!-- YAML
39113948
added: v0.1.90
3949+
changes:
3950+
- version: REPLACEME
3951+
pr-url: https://github.com/nodejs/node/pull/56578
3952+
description: supports Uint8Array as `this` value.
39123953
-->
39133954

39143955
* `string` {string} String to write to `buf`.
Collapse file

‎lib/buffer.js‎

Copy file name to clipboardExpand all lines: lib/buffer.js
+37-24Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,17 @@ const {
7272
kStringMaxLength,
7373
atob: _atob,
7474
btoa: _btoa,
75+
asciiSlice,
76+
base64Slice,
77+
base64urlSlice,
78+
latin1Slice,
79+
hexSlice,
80+
ucs2Slice,
81+
utf8Slice,
82+
base64Write,
83+
base64urlWrite,
84+
hexWrite,
85+
ucs2Write,
7586
} = internalBinding('buffer');
7687
const {
7788
constants: {
@@ -127,6 +138,9 @@ const {
127138
markAsUntransferable,
128139
addBufferPrototypeMethods,
129140
createUnsafeBuffer,
141+
asciiWrite,
142+
latin1Write,
143+
utf8Write,
130144
} = require('internal/buffer');
131145

132146
FastBuffer.prototype.constructor = Buffer;
@@ -634,44 +648,44 @@ const encodingOps = {
634648
encoding: 'utf8',
635649
encodingVal: encodingsMap.utf8,
636650
byteLength: byteLengthUtf8,
637-
write: (buf, string, offset, len) => buf.utf8Write(string, offset, len),
638-
slice: (buf, start, end) => buf.utf8Slice(start, end),
651+
write: utf8Write,
652+
slice: utf8Slice,
639653
indexOf: (buf, val, byteOffset, dir) =>
640654
indexOfString(buf, val, byteOffset, encodingsMap.utf8, dir),
641655
},
642656
ucs2: {
643657
encoding: 'ucs2',
644658
encodingVal: encodingsMap.utf16le,
645659
byteLength: (string) => string.length * 2,
646-
write: (buf, string, offset, len) => buf.ucs2Write(string, offset, len),
647-
slice: (buf, start, end) => buf.ucs2Slice(start, end),
660+
write: ucs2Write,
661+
slice: ucs2Slice,
648662
indexOf: (buf, val, byteOffset, dir) =>
649663
indexOfString(buf, val, byteOffset, encodingsMap.utf16le, dir),
650664
},
651665
utf16le: {
652666
encoding: 'utf16le',
653667
encodingVal: encodingsMap.utf16le,
654668
byteLength: (string) => string.length * 2,
655-
write: (buf, string, offset, len) => buf.ucs2Write(string, offset, len),
656-
slice: (buf, start, end) => buf.ucs2Slice(start, end),
669+
write: ucs2Write,
670+
slice: ucs2Slice,
657671
indexOf: (buf, val, byteOffset, dir) =>
658672
indexOfString(buf, val, byteOffset, encodingsMap.utf16le, dir),
659673
},
660674
latin1: {
661675
encoding: 'latin1',
662676
encodingVal: encodingsMap.latin1,
663677
byteLength: (string) => string.length,
664-
write: (buf, string, offset, len) => buf.latin1Write(string, offset, len),
665-
slice: (buf, start, end) => buf.latin1Slice(start, end),
678+
write: latin1Write,
679+
slice: latin1Slice,
666680
indexOf: (buf, val, byteOffset, dir) =>
667681
indexOfString(buf, val, byteOffset, encodingsMap.latin1, dir),
668682
},
669683
ascii: {
670684
encoding: 'ascii',
671685
encodingVal: encodingsMap.ascii,
672686
byteLength: (string) => string.length,
673-
write: (buf, string, offset, len) => buf.asciiWrite(string, offset, len),
674-
slice: (buf, start, end) => buf.asciiSlice(start, end),
687+
write: asciiWrite,
688+
slice: asciiSlice,
675689
indexOf: (buf, val, byteOffset, dir) =>
676690
indexOfBuffer(buf,
677691
fromStringFast(val, encodingOps.ascii),
@@ -683,8 +697,8 @@ const encodingOps = {
683697
encoding: 'base64',
684698
encodingVal: encodingsMap.base64,
685699
byteLength: (string) => base64ByteLength(string, string.length),
686-
write: (buf, string, offset, len) => buf.base64Write(string, offset, len),
687-
slice: (buf, start, end) => buf.base64Slice(start, end),
700+
write: base64Write,
701+
slice: base64Slice,
688702
indexOf: (buf, val, byteOffset, dir) =>
689703
indexOfBuffer(buf,
690704
fromStringFast(val, encodingOps.base64),
@@ -696,9 +710,8 @@ const encodingOps = {
696710
encoding: 'base64url',
697711
encodingVal: encodingsMap.base64url,
698712
byteLength: (string) => base64ByteLength(string, string.length),
699-
write: (buf, string, offset, len) =>
700-
buf.base64urlWrite(string, offset, len),
701-
slice: (buf, start, end) => buf.base64urlSlice(start, end),
713+
write: base64urlWrite,
714+
slice: base64urlSlice,
702715
indexOf: (buf, val, byteOffset, dir) =>
703716
indexOfBuffer(buf,
704717
fromStringFast(val, encodingOps.base64url),
@@ -710,8 +723,8 @@ const encodingOps = {
710723
encoding: 'hex',
711724
encodingVal: encodingsMap.hex,
712725
byteLength: (string) => string.length >>> 1,
713-
write: (buf, string, offset, len) => buf.hexWrite(string, offset, len),
714-
slice: (buf, start, end) => buf.hexSlice(start, end),
726+
write: hexWrite,
727+
slice: hexSlice,
715728
indexOf: (buf, val, byteOffset, dir) =>
716729
indexOfBuffer(buf,
717730
fromStringFast(val, encodingOps.hex),
@@ -836,7 +849,7 @@ Buffer.prototype.copy =
836849
// to their upper/lower bounds if the value passed is out of range.
837850
Buffer.prototype.toString = function toString(encoding, start, end) {
838851
if (arguments.length === 0) {
839-
return this.utf8Slice(0, this.length);
852+
return utf8Slice(this, 0, this.length);
840853
}
841854

842855
const len = this.length;
@@ -857,7 +870,7 @@ Buffer.prototype.toString = function toString(encoding, start, end) {
857870
return '';
858871

859872
if (encoding === undefined)
860-
return this.utf8Slice(start, end);
873+
return utf8Slice(this, start, end);
861874

862875
const ops = getEncodingOps(encoding);
863876
if (ops === undefined)
@@ -888,7 +901,7 @@ Buffer.prototype[customInspectSymbol] = function inspect(recurseTimes, ctx) {
888901
const actualMax = MathMin(max, this.length);
889902
const remaining = this.length - max;
890903
let str = StringPrototypeTrim(RegExpPrototypeSymbolReplace(
891-
/(.{2})/g, this.hexSlice(0, actualMax), '$1 '));
904+
/(.{2})/g, hexSlice(this, 0, actualMax), '$1 '));
892905
if (remaining > 0)
893906
str += ` ... ${remaining} more byte${remaining > 1 ? 's' : ''}`;
894907
// Inspect special properties as well, if possible.
@@ -1027,7 +1040,7 @@ Buffer.prototype.lastIndexOf = function lastIndexOf(val, byteOffset, encoding) {
10271040
};
10281041

10291042
Buffer.prototype.includes = function includes(val, byteOffset, encoding) {
1030-
return this.indexOf(val, byteOffset, encoding) !== -1;
1043+
return bidirectionalIndexOf(this, val, byteOffset, encoding, true) !== -1;
10311044
};
10321045

10331046
// Usage:
@@ -1112,7 +1125,7 @@ function _fill(buf, value, offset, end, encoding) {
11121125
Buffer.prototype.write = function write(string, offset, length, encoding) {
11131126
// Buffer#write(string);
11141127
if (offset === undefined) {
1115-
return this.utf8Write(string, 0, this.length);
1128+
return utf8Write(this, string, 0, this.length);
11161129
}
11171130
// Buffer#write(string, encoding)
11181131
if (length === undefined && typeof offset === 'string') {
@@ -1139,9 +1152,9 @@ Buffer.prototype.write = function write(string, offset, length, encoding) {
11391152
}
11401153

11411154
if (!encoding || encoding === 'utf8')
1142-
return this.utf8Write(string, offset, length);
1155+
return utf8Write(this, string, offset, length);
11431156
if (encoding === 'ascii')
1144-
return this.asciiWrite(string, offset, length);
1157+
return asciiWrite(this, string, offset, length);
11451158

11461159
const ops = getEncodingOps(encoding);
11471160
if (ops === undefined)

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.