Repository: electron/electron
Pull request: fix: -Wunsafe-buffer-usage warnings in url-loader

#### Description of Change

Part 2 in a [series](https://github.com/electron/electron/pull/43477) to fix `-Wunsafe-buffer-usage` warnings in electron `shell/`.

This PR fixes warnings in `electron_api_url_loader.cc` by using [v8::ArrayBufferView::CopyContents()](https://chromium.googlesource.com/v8/v8/+/287f5002404a3d08df6b42de1081f89ace1927ea/include/v8-array-buffer.h#386) instead of doing the pointer math ourselves. This fixes the warnings, results in simpler code, and may also avoid some additional overhead:

> Copy the contents of the ArrayBufferView's buffer to an
> embedder defined memory without additional overhead that
> calling ArrayBufferView::Buffer might incur.

Warnings fixed by this PR:

```
../../electron/shell/common/api/electron_api_url_loader.cc:250:24: error: function introduces unsafe buffer manipulation [-Werror,-Wunsafe-buffer-usage]
  250 |     auto buffer_span = base::make_span(
      |                        ^~~~~~~~~~~~~~~~
  251 |         static_cast<char*>(backing_store->Data()) + buffer->ByteOffset(),
      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  252 |         buffer->ByteLength());
      |         ~~~~~~~~~~~~~~~~~~~~~
../../electron/shell/common/api/electron_api_url_loader.cc:250:24: note: pass -fsafe-buffer-usage-suggestions to receive code hardening suggestions
../../electron/shell/common/api/electron_api_url_loader.cc:251:9: error: unsafe pointer arithmetic [-Werror,-Wunsafe-buffer-usage]
  251 |         static_cast<char*>(backing_store->Data()) + buffer->ByteOffset(),
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../../electron/shell/common/api/electron_api_url_loader.cc:251:9: note: pass -fsafe-buffer-usage-suggestions to receive code hardening suggestions
../../electron/shell/common/api/electron_api_url_loader.cc:665:11: error: unsafe pointer arithmetic [-Werror,-Wunsafe-buffer-usage]
  665 |           static_cast<char*>(backing_store->Data()) + buffer_body->ByteOffset(),
      |           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../../electron/shell/common/api/electron_api_url_loader.cc:665:11: note: pass -fsafe-buffer-usage-suggestions to receive code hardening suggestions
266 errors generated.
```

#### Checklist

- [x] PR description included and stakeholders cc'd
- [x] `npm test` passes
- [x] [PR release notes](https://github.com/electron/clerk/blob/main/README.md) describe the change in a way relevant to app developers, and are [capitalized, punctuated, and past tense](https://github.com/electron/clerk/blob/main/README.md#examples).

#### Release Notes

Notes: none.

Changed files:
filename: shell/common/api/electron_api_url_loader.cc
patch: @@ -11,6 +11,7 @@
 #include <utility>
 #include <vector>
 
+#include "base/check_op.h"
 #include "base/containers/fixed_flat_map.h"
 #include "base/memory/raw_ptr.h"
 #include "base/no_destructor.h"
@@ -131,12 +132,21 @@ namespace electron::api {
 
 namespace {
 
+template <typename T>
+auto ToVec(v8::Local<v8::ArrayBufferView> view) {
+  const size_t n_wanted = view->ByteLength();
+  std::vector<T> buf(n_wanted);
+  [[maybe_unused]] const auto n_got = view->CopyContents(buf.data(), n_wanted);
+  DCHECK_EQ(n_wanted, n_got);
+  DCHECK_EQ(n_wanted, std::size(buf));
+  return buf;
+}
+
 class BufferDataSource : public mojo::DataPipeProducer::DataSource {
  public:
-  explicit BufferDataSource(base::span<char> buffer) {
-    buffer_.resize(buffer.size());
-    memcpy(buffer_.data(), buffer.data(), buffer_.size());
-  }
+  explicit BufferDataSource(v8::Local<v8::ArrayBufferView> buffer)
+      : buffer_{ToVec<char>(buffer)} {}
+
   ~BufferDataSource() override = default;
 
  private:
@@ -247,13 +257,8 @@ class JSChunkedDataPipeGetter final
     auto buffer = buffer_val.As<v8::ArrayBufferView>();
     is_writing_ = true;
     bytes_written_ += buffer->ByteLength();
-    auto backing_store = buffer->Buffer()->GetBackingStore();
-    auto buffer_span = base::make_span(
-        static_cast<char*>(backing_store->Data()) + buffer->ByteOffset(),
-        buffer->ByteLength());
-    auto buffer_source = std::make_unique<BufferDataSource>(buffer_span);
     data_producer_->Write(
-        std::move(buffer_source),
+        std::make_unique<BufferDataSource>(buffer),
         base::BindOnce(&JSChunkedDataPipeGetter::OnWriteChunkComplete,
                        // We're OK to use Unretained here because we own
                        // |data_producer_|.
@@ -660,11 +665,9 @@ gin::Handle<SimpleURLLoaderWrapper> SimpleURLLoaderWrapper::Create(
   v8::Local<v8::Value> chunk_pipe_getter;
   if (opts.Get("body", &body)) {
     if (body->IsArrayBufferView()) {
-      auto buffer_body = body.As<v8::ArrayBufferView>();
-      auto backing_store = buffer_body->Buffer()->GetBackingStore();
-      request->request_body = network::ResourceRequestBody::CreateFromBytes(
-          static_cast<char*>(backing_store->Data()) + buffer_body->ByteOffset(),
-          buffer_body->ByteLength());
+      auto request_body = base::MakeRefCounted<network::ResourceRequestBody>();
+      request_body->AppendBytes(ToVec<uint8_t>(body.As<v8::ArrayBufferView>()));
+      request->request_body = std::move(request_body);
     } else if (body->IsFunction()) {
       auto body_func = body.As<v8::Function>();