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 bbeb38d

Browse filesBrowse files
ronagaduh95
authored andcommitted
buffer: fix end parameter bugs in indexOf/lastIndexOf
- Fix FastIndexOfNumber parameter order mismatch (end_i64 and is_forward were swapped vs the JS call site and slow path) - Clamp negative end values to 0 to prevent size_t overflow in IndexOfString, IndexOfBuffer, and IndexOfNumberImpl - Clamp empty needle result to search_end Signed-off-by: Robert Nagy <ronagy@icloud.com> Assisted-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> PR-URL: #62711 Fixes: #62873 Reviewed-By: Filip Skokan <panva.ip@gmail.com> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
1 parent 7a52fd0 commit bbeb38d
Copy full SHA for bbeb38d

2 files changed

+50-11Lines changed: 50 additions & 11 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

‎src/node_buffer.cc‎

Copy file name to clipboardExpand all lines: src/node_buffer.cc
+15-11Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -983,8 +983,8 @@ void IndexOfString(const FunctionCallbackInfo<Value>& args) {
983983
if (!StringBytes::Size(isolate, needle, enc).To(&needle_length)) return;
984984

985985
// search_end is the exclusive upper bound of the search range.
986-
size_t search_end = static_cast<size_t>(
987-
std::min(end_i64, static_cast<int64_t>(haystack_length)));
986+
size_t search_end = static_cast<size_t>(std::min(
987+
std::max(end_i64, int64_t{0}), static_cast<int64_t>(haystack_length)));
988988
if (enc == UCS2) search_end &= ~static_cast<size_t>(1);
989989

990990
int64_t opt_offset = IndexOfOffset(haystack_length,
@@ -993,8 +993,10 @@ void IndexOfString(const FunctionCallbackInfo<Value>& args) {
993993
is_forward);
994994

995995
if (needle_length == 0) {
996-
// Match String#indexOf() and String#lastIndexOf() behavior.
997-
args.GetReturnValue().Set(static_cast<double>(opt_offset));
996+
// Match String#indexOf() and String#lastIndexOf() behavior,
997+
// but clamp to search_end.
998+
int64_t clamped = std::min(opt_offset, static_cast<int64_t>(search_end));
999+
args.GetReturnValue().Set(static_cast<double>(clamped));
9981000
return;
9991001
}
10001002

@@ -1108,8 +1110,8 @@ void IndexOfBuffer(const FunctionCallbackInfo<Value>& args) {
11081110
const size_t needle_length = needle_contents.length();
11091111

11101112
// search_end is the exclusive upper bound of the search range.
1111-
size_t search_end = static_cast<size_t>(
1112-
std::min(end_i64, static_cast<int64_t>(haystack_length)));
1113+
size_t search_end = static_cast<size_t>(std::min(
1114+
std::max(end_i64, int64_t{0}), static_cast<int64_t>(haystack_length)));
11131115
if (enc == UCS2) search_end &= ~static_cast<size_t>(1);
11141116

11151117
int64_t opt_offset = IndexOfOffset(haystack_length,
@@ -1118,8 +1120,10 @@ void IndexOfBuffer(const FunctionCallbackInfo<Value>& args) {
11181120
is_forward);
11191121

11201122
if (needle_length == 0) {
1121-
// Match String#indexOf() and String#lastIndexOf() behavior.
1122-
args.GetReturnValue().Set(static_cast<double>(opt_offset));
1123+
// Match String#indexOf() and String#lastIndexOf() behavior,
1124+
// but clamp to search_end.
1125+
int64_t clamped = std::min(opt_offset, static_cast<int64_t>(search_end));
1126+
args.GetReturnValue().Set(static_cast<double>(clamped));
11231127
return;
11241128
}
11251129

@@ -1184,8 +1188,8 @@ int32_t IndexOfNumberImpl(Local<Value> buffer_obj,
11841188
}
11851189
size_t offset = static_cast<size_t>(opt_offset);
11861190
// search_end is the exclusive upper bound of the search range.
1187-
size_t search_end = static_cast<size_t>(
1188-
std::min(end_i64, static_cast<int64_t>(buffer_length)));
1191+
size_t search_end = static_cast<size_t>(std::min(
1192+
std::max(end_i64, int64_t{0}), static_cast<int64_t>(buffer_length)));
11891193

11901194
const void* ptr;
11911195
if (is_forward) {
@@ -1222,8 +1226,8 @@ int32_t FastIndexOfNumber(Local<Value>,
12221226
Local<Value> buffer_obj,
12231227
uint32_t needle,
12241228
int64_t offset_i64,
1225-
int64_t end_i64,
12261229
bool is_forward,
1230+
int64_t end_i64,
12271231
// NOLINTNEXTLINE(runtime/references)
12281232
FastApiCallbackOptions& options) {
12291233
HandleScope scope(options.isolate);
Collapse file

‎test/parallel/test-buffer-indexof.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-buffer-indexof.js
+35Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,3 +691,38 @@ assert.strictEqual(reallyLong.lastIndexOf(pattern), 0);
691691

692692
assert.strictEqual(buf.includes('c'), true);
693693
}
694+
695+
{
696+
const buf = Buffer.from('abcabc');
697+
698+
// Negative end should be treated as 0 (no match possible).
699+
assert.strictEqual(buf.indexOf('a', 0, -1), -1);
700+
assert.strictEqual(buf.indexOf('a', 0, -100), -1);
701+
assert.strictEqual(buf.indexOf(0x61, 0, -1), -1);
702+
assert.strictEqual(buf.lastIndexOf('a', 5, -1), -1);
703+
assert.strictEqual(buf.lastIndexOf(0x61, 5, -1), -1);
704+
assert.strictEqual(buf.includes('a', 0, -1), false);
705+
assert.strictEqual(buf.indexOf(Buffer.from('a'), 0, -1), -1);
706+
assert.strictEqual(buf.lastIndexOf(Buffer.from('a'), 5, -1), -1);
707+
708+
// End = 0 means empty search range.
709+
assert.strictEqual(buf.indexOf('a', 0, 0), -1);
710+
assert.strictEqual(buf.indexOf(0x61, 0, 0), -1);
711+
assert.strictEqual(buf.lastIndexOf('a', 5, 0), -1);
712+
assert.strictEqual(buf.lastIndexOf(0x61, 5, 0), -1);
713+
714+
// End greater than buffer length should be clamped.
715+
assert.strictEqual(buf.indexOf('c', 0, 100), 2);
716+
assert.strictEqual(buf.indexOf(0x63, 0, 100), 2);
717+
assert.strictEqual(buf.lastIndexOf('c', 5, 100), 5);
718+
assert.strictEqual(buf.lastIndexOf(0x63, 5, 100), 5);
719+
assert.strictEqual(buf.indexOf(Buffer.from('c'), 0, 100), 2);
720+
721+
// Empty needle with end parameter should clamp to search_end.
722+
assert.strictEqual(buf.indexOf('', 0, 3), 0);
723+
assert.strictEqual(buf.indexOf('', 5, 3), 3);
724+
assert.strictEqual(buf.indexOf(Buffer.from(''), 5, 3), 3);
725+
assert.strictEqual(buf.indexOf('', 0, 0), 0);
726+
assert.strictEqual(buf.lastIndexOf('', 5, 3), 3);
727+
assert.strictEqual(buf.lastIndexOf(Buffer.from(''), 5, 3), 3);
728+
}

0 commit comments

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