Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions src/node_buffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -578,9 +578,28 @@ void CopyImpl(Local<Value> source_obj,
void SlowCopy(const FunctionCallbackInfo<Value>& args) {
Local<Value> source_obj = args[0];
Local<Value> target_obj = args[1];
Environment* env = Environment::GetCurrent(args);
Isolate* isolate = env->isolate();

// Add validation before call CopyImpl blindly
if (!Buffer::HasInstance(source_obj) || !Buffer::HasInstance(target_obj)) {
isolate->ThrowException(v8::Exception::TypeError(String::NewFromUtf8Literal(
isolate, "Arguments must be Buffer instances")));
return;
}
const uint32_t target_start = args[2].As<Uint32>()->Value();
const uint32_t source_start = args[3].As<Uint32>()->Value();
const uint32_t to_copy = args[4].As<Uint32>()->Value();
size_t source_len = Buffer::Length(source_obj.As<Object>());
size_t target_len = Buffer::Length(target_obj.As<Object>());

if (source_start > source_len || target_start > target_len ||
to_copy > source_len - source_start ||
to_copy > target_len - target_start) {
isolate->ThrowException(v8::Exception::RangeError(
String::NewFromUtf8Literal(isolate, "Buffer copy out of range")));
return;
}

CopyImpl(source_obj, target_obj, target_start, source_start, to_copy);

Expand All @@ -597,7 +616,21 @@ uint32_t FastCopy(Local<Value> receiver,
// NOLINTNEXTLINE(runtime/references)
FastApiCallbackOptions& options) {
HandleScope scope(options.isolate);
Isolate* isolate = options.isolate;

if (!node::Buffer::HasInstance(source_obj) ||
!node::Buffer::HasInstance(target_obj)) {
return 0;
}
// Validate First before call CopyImpl blindly
size_t src_len = Buffer::Length(source_obj.As<v8::Object>());
size_t dst_len = Buffer::Length(target_obj.As<v8::Object>());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just fyi, Buffer::HasInstance(obj) is an alias for obj->IsArrayBufferView() and Buffer::Length(obj) is an alias for obj.As<ArrayBufferView>()->ByteLength(). I'd suggest just using those here directly

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the note you’re absolutely right. I’ve updated the code to use IsArrayBufferView() and ByteLength() directly instead of Buffer::HasInstance() and Buffer::Length() for consistency with the V8 API.


if (source_start > src_len || target_start > dst_len ||
to_copy > src_len - source_start || to_copy > dst_len - target_start) {
// options.fallback = true; // Let JS slow path handle it (safe fallback)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be an unresolved comment here? We don't do fallbacks anymore, but we still need to handle the situation in this case.

Maybe we could return -1 and check for that on the JS side?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You’re right, returning a sentinel like -1 would be clearer to signal an invalid range. However, since the function currently returns a uint32_t, using -1 would actually wrap around to 4294967295, which could cause unexpected behavior.

If we want to use -1 safely, we should change the return type to int32_t so the error code is properly represented.

return 0;
}
CopyImpl(source_obj, target_obj, target_start, source_start, to_copy);

return to_copy;
Expand Down