Skip to content

Commit fd4dc5c

Browse files
committed
buffer: prevent assertion crash in indexOf when encoding is non-numeric
When buf.indexOf(val, offset, encoding) or lastIndexOf/includes was called with a non-string/non-numeric value (such as null or an object) for encoding, end was left as that value instead of defaulting to buffer length. This caused C++ CHECK assertions (args[end_idx]->IsNumber()) to fail and crash the process with SIGABRT. Normalize non-numeric 3rd arguments to buffer length and ensure end is coerced to a number in bidirectionalIndexOf. Signed-off-by: Nik <84yk8btb9f@privaterelay.appleid.com>
1 parent 8587d71 commit fd4dc5c

2 files changed

Lines changed: 96 additions & 3 deletions

File tree

‎lib/buffer.js‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,6 +1131,13 @@ function bidirectionalIndexOf(buffer, val, byteOffset, end, encoding, dir) {
11311131
}
11321132
dir = !!dir; // Cast to bool.
11331133

1134+
if (typeof end !== 'number') {
1135+
end = +end;
1136+
if (NumberIsNaN(end)) {
1137+
end = buffer.length || buffer.byteLength;
1138+
}
1139+
}
1140+
11341141
if (typeof val === 'number')
11351142
return indexOfNumber(buffer, val >>> 0, byteOffset, dir, end);
11361143

@@ -1158,7 +1165,7 @@ function bidirectionalIndexOf(buffer, val, byteOffset, end, encoding, dir) {
11581165
}
11591166

11601167
Buffer.prototype.indexOf = function indexOf(val, offset, end, encoding) {
1161-
if (typeof end === 'string') {
1168+
if (encoding === undefined && typeof end !== 'number') {
11621169
encoding = end;
11631170
end = this.length;
11641171
} else if (end === undefined) {
@@ -1168,7 +1175,7 @@ Buffer.prototype.indexOf = function indexOf(val, offset, end, encoding) {
11681175
};
11691176

11701177
Buffer.prototype.lastIndexOf = function lastIndexOf(val, offset, end, encoding) {
1171-
if (typeof end === 'string') {
1178+
if (encoding === undefined && typeof end !== 'number') {
11721179
encoding = end;
11731180
end = this.length;
11741181
} else if (end === undefined) {
@@ -1178,7 +1185,7 @@ Buffer.prototype.lastIndexOf = function lastIndexOf(val, offset, end, encoding)
11781185
};
11791186

11801187
Buffer.prototype.includes = function includes(val, offset, end, encoding) {
1181-
if (typeof end === 'string') {
1188+
if (encoding === undefined && typeof end !== 'number') {
11821189
encoding = end;
11831190
end = this.length;
11841191
} else if (end === undefined) {
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
'use strict';
2+
const common = require('../common');
3+
const assert = require('assert');
4+
5+
const b = Buffer.from('abcdef');
6+
7+
// 3-argument calls: buf.indexOf(val, offset, encoding) where encoding is null
8+
assert.strictEqual(b.indexOf(0x62, 0, null), 1);
9+
assert.strictEqual(b.indexOf(Buffer.from('b'), 0, null), 1);
10+
assert.strictEqual(b.indexOf(new Uint8Array([0x62]), 0, null), 1);
11+
assert.throws(() => b.indexOf('b', 0, null), {
12+
code: 'ERR_UNKNOWN_ENCODING',
13+
});
14+
15+
// Non-string object encoding in 3-argument calls
16+
assert.strictEqual(b.indexOf(0x62, 0, {}), 1);
17+
assert.strictEqual(b.indexOf(Buffer.from('b'), 0, {}), 1);
18+
assert.throws(() => b.indexOf('b', 0, {}), {
19+
code: 'ERR_UNKNOWN_ENCODING',
20+
});
21+
22+
// 3-argument calls with false encoding
23+
assert.strictEqual(b.indexOf(0x62, 0, false), 1);
24+
assert.strictEqual(b.indexOf(Buffer.from('b'), 0, false), 1);
25+
assert.throws(() => b.indexOf('b', 0, false), {
26+
code: 'ERR_UNKNOWN_ENCODING',
27+
});
28+
29+
// lastIndexOf with null and non-string encoding
30+
assert.strictEqual(b.lastIndexOf(0x62, 5, null), 1);
31+
assert.strictEqual(b.lastIndexOf(Buffer.from('b'), 5, null), 1);
32+
assert.strictEqual(b.lastIndexOf(new Uint8Array([0x62]), 5, null), 1);
33+
assert.throws(() => b.lastIndexOf('b', 5, null), {
34+
code: 'ERR_UNKNOWN_ENCODING',
35+
});
36+
assert.strictEqual(b.lastIndexOf(0x62, 5, {}), 1);
37+
assert.strictEqual(b.lastIndexOf(Buffer.from('b'), 5, {}), 1);
38+
assert.throws(() => b.lastIndexOf('b', 5, {}), {
39+
code: 'ERR_UNKNOWN_ENCODING',
40+
});
41+
42+
// includes with null and non-string encoding
43+
assert.strictEqual(b.includes(0x62, 0, null), true);
44+
assert.strictEqual(b.includes(Buffer.from('b'), 0, null), true);
45+
assert.strictEqual(b.includes(new Uint8Array([0x62]), 0, null), true);
46+
assert.throws(() => b.includes('b', 0, null), {
47+
code: 'ERR_UNKNOWN_ENCODING',
48+
});
49+
assert.strictEqual(b.includes(0x62, 0, {}), true);
50+
assert.strictEqual(b.includes(Buffer.from('b'), 0, {}), true);
51+
assert.throws(() => b.includes('b', 0, {}), {
52+
code: 'ERR_UNKNOWN_ENCODING',
53+
});
54+
55+
// 2-argument calls where byteOffset is null
56+
assert.strictEqual(b.indexOf('b', null), 1);
57+
assert.strictEqual(b.indexOf(0x62, null), 1);
58+
assert.strictEqual(b.indexOf(Buffer.from('b'), null), 1);
59+
assert.strictEqual(b.lastIndexOf('b', null), -1);
60+
assert.strictEqual(b.lastIndexOf(0x62, null), -1);
61+
assert.strictEqual(b.lastIndexOf(Buffer.from('b'), null), -1);
62+
assert.strictEqual(b.includes('b', null), true);
63+
assert.strictEqual(b.includes(0x62, null), true);
64+
assert.strictEqual(b.includes(Buffer.from('b'), null), true);
65+
66+
// 3-argument calls where byteOffset is null and encoding is null
67+
assert.strictEqual(b.indexOf(0x62, null, null), 1);
68+
assert.strictEqual(b.indexOf(Buffer.from('b'), null, null), 1);
69+
assert.throws(() => b.indexOf('b', null, null), {
70+
code: 'ERR_UNKNOWN_ENCODING',
71+
});
72+
assert.strictEqual(b.includes(0x62, null, null), true);
73+
assert.strictEqual(b.includes(Buffer.from('b'), null, null), true);
74+
assert.throws(() => b.includes('b', null, null), {
75+
code: 'ERR_UNKNOWN_ENCODING',
76+
});
77+
78+
// 3-argument calls with numeric end bounds still work as expected
79+
assert.strictEqual(b.indexOf('b', 0, 1), -1);
80+
assert.strictEqual(b.indexOf('b', 0, 2), 1);
81+
assert.strictEqual(b.indexOf(0x62, 0, 1), -1);
82+
assert.strictEqual(b.indexOf(0x62, 0, 2), 1);
83+
assert.strictEqual(b.indexOf(Buffer.from('b'), 0, 1), -1);
84+
assert.strictEqual(b.indexOf(Buffer.from('b'), 0, 2), 1);
85+
assert.strictEqual(b.includes('b', 0, 1), false);
86+
assert.strictEqual(b.includes('b', 0, 2), true);

0 commit comments

Comments
 (0)