Skip to content

Commit 4401575

Browse files
addaleaxevanlucas
authored andcommitted
buffer: fix lastIndexOf index underflow issue
Fix `buffer.lastIndexOf()` for the case that the first character of the needle is contained in the haystack, but in a location that makes it impossible to be part of a full match. For example, when searching for 'abc' in 'abcdef', only the 'cdef' part needs to be searched for 'c', because earlier locations can be excluded by index calculations alone. Previously, such a search would result in an assertion failure. This applies only to Node.js v6, as `lastIndexOf` was added in it. PR-URL: #6511 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Trevor Norris <[email protected]>
1 parent 6aa92d5 commit 4401575

File tree

2 files changed

+24
-5
lines changed

2 files changed

+24
-5
lines changed

src/string_search.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -261,19 +261,19 @@ inline size_t FindFirstCharacter(Vector<const Char> pattern,
261261
const uint8_t search_byte = GetHighestValueByte(pattern_first_char);
262262
size_t pos = index;
263263
do {
264-
size_t bytes_to_search;
264+
const size_t bytes_to_search = (max_n - pos) * sizeof(Char);
265265
const void* void_pos;
266266
if (subject.forward()) {
267267
// Assert that bytes_to_search won't overflow
268268
CHECK_LE(pos, max_n);
269269
CHECK_LE(max_n - pos, SIZE_MAX / sizeof(Char));
270-
bytes_to_search = (max_n - pos) * sizeof(Char);
271270
void_pos = memchr(subject.start() + pos, search_byte, bytes_to_search);
272271
} else {
273272
CHECK_LE(pos, subject.length());
274273
CHECK_LE(subject.length() - pos, SIZE_MAX / sizeof(Char));
275-
bytes_to_search = (subject.length() - pos) * sizeof(Char);
276-
void_pos = MemrchrFill(subject.start(), search_byte, bytes_to_search);
274+
void_pos = MemrchrFill(subject.start() + pattern.length() - 1,
275+
search_byte,
276+
bytes_to_search);
277277
}
278278
const Char* char_pos = static_cast<const Char*>(void_pos);
279279
if (char_pos == nullptr)
@@ -308,7 +308,9 @@ inline size_t FindFirstCharacter(Vector<const uint8_t> pattern,
308308
if (subject.forward()) {
309309
pos = memchr(subject.start() + index, pattern_first_char, max_n - index);
310310
} else {
311-
pos = MemrchrFill(subject.start(), pattern_first_char, subj_len - index);
311+
pos = MemrchrFill(subject.start() + pattern.length() - 1,
312+
pattern_first_char,
313+
max_n - index);
312314
}
313315
const uint8_t* char_pos = static_cast<const uint8_t*>(pos);
314316
if (char_pos == nullptr) {

test/parallel/test-buffer-indexof.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,23 @@ assert.equal(13, bufferString.lastIndexOf('a ', -1));
359359
assert.equal(0, bufferString.lastIndexOf('a ', -27));
360360
assert.equal(-1, bufferString.lastIndexOf('a ', -28));
361361

362+
// Test lastIndexOf for the case that the first character can be found,
363+
// but in a part of the buffer that does not make search to search
364+
// due do length constraints.
365+
const abInUCS2 = Buffer.from('ab', 'ucs2');
366+
assert.strictEqual(-1, Buffer.from('µaaaa¶bbbb', 'binary').lastIndexOf('µ'));
367+
assert.strictEqual(-1, Buffer.from('bc').lastIndexOf('ab'));
368+
assert.strictEqual(-1, Buffer.from('abc').lastIndexOf('qa'));
369+
assert.strictEqual(-1, Buffer.from('abcdef').lastIndexOf('qabc'));
370+
assert.strictEqual(-1, Buffer.from('bc').lastIndexOf(Buffer.from('ab')));
371+
assert.strictEqual(-1, Buffer.from('bc', 'ucs2').lastIndexOf('ab', 'ucs2'));
372+
assert.strictEqual(-1, Buffer.from('bc', 'ucs2').lastIndexOf(abInUCS2));
373+
374+
assert.strictEqual(0, Buffer.from('abc').lastIndexOf('ab'));
375+
assert.strictEqual(0, Buffer.from('abc').lastIndexOf('ab', 1));
376+
assert.strictEqual(0, Buffer.from('abc').lastIndexOf('ab', 2));
377+
assert.strictEqual(0, Buffer.from('abc').lastIndexOf('ab', 3));
378+
362379
// The above tests test the LINEAR and SINGLE-CHAR strategies.
363380
// Now, we test the BOYER-MOORE-HORSPOOL strategy.
364381
// Test lastIndexOf on a long buffer w multiple matches:

0 commit comments

Comments
 (0)