Repository: electron/electron
Pull request: fix: -Wunsafe-buffer-usage warnings when read()ing and write()ing integers

#### Description of Change

Part 17 in a [series](https://github.com/electron/electron/pull/43477) to fix `-Wunsafe-buffer-usage` warnings in Electron `shell/`.  This PR fixes warnings generated when `read()`ing and `write()`ing an `int` type during shutdown handling in `ElectronBrowserMainParts`.

Warnings fixed by this PR:

```
../../electron/shell/browser/electron_browser_main_parts_posix.cc:56:15: error: unsafe pointer arithmetic [-Werror,-Wunsafe-buffer-u
sage]
   56 |               reinterpret_cast<const char*>(&signal) + bytes_written,
      |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../../base/posix/eintr_wrapper.h:31:29: note: expanded from macro 'HANDLE_EINTR'
   31 |     eintr_wrapper_result = (x); \
      |                             ^
../../electron/shell/browser/electron_browser_main_parts_posix.cc:56:15: note: See //docs/unsafe_buffers.md for help.
../../electron/shell/browser/electron_browser_main_parts_posix.cc:140:28: error: unsafe pointer arithmetic [-Werror,-Wunsafe-buffer-
usage]
  140 |         read(shutdown_fd_, reinterpret_cast<char*>(&signal) + bytes_read,
      |                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../../base/posix/eintr_wrapper.h:31:29: note: expanded from macro 'HANDLE_EINTR'
   31 |     eintr_wrapper_result = (x); \
      |                             ^
../../electron/shell/browser/electron_browser_main_parts_posix.cc:140:28: note: See //docs/unsafe_buffers.md for help.
```

#### 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/browser/electron_browser_main_parts_posix.cc
patch: @@ -25,6 +25,18 @@ namespace electron {
 
 namespace {
 
+// write |ref|'s raw bytes to |fd|.
+template <typename T>
+void WriteValToFd(int fd, const T& ref) {
+  base::span<const uint8_t> bytes = base::byte_span_from_ref(ref);
+  while (!bytes.empty()) {
+    const ssize_t rv = HANDLE_EINTR(write(fd, bytes.data(), bytes.size()));
+    RAW_CHECK(rv >= 0);
+    const size_t n_bytes_written = rv >= 0 ? static_cast<size_t>(rv) : 0U;
+    bytes = bytes.subspan(n_bytes_written);
+  }
+}
+
 // See comment in |PreEarlyInitialization()|, where sigaction is called.
 void SIGCHLDHandler(int signal) {}
 
@@ -49,15 +61,7 @@ void GracefulShutdownHandler(int signal) {
   RAW_CHECK(g_pipe_pid == getpid());
   RAW_CHECK(g_shutdown_pipe_write_fd != -1);
   RAW_CHECK(g_shutdown_pipe_read_fd != -1);
-  size_t bytes_written = 0;
-  do {
-    int rv = HANDLE_EINTR(
-        write(g_shutdown_pipe_write_fd,
-              reinterpret_cast<const char*>(&signal) + bytes_written,
-              sizeof(signal) - bytes_written));
-    RAW_CHECK(rv >= 0);
-    bytes_written += rv;
-  } while (bytes_written < sizeof(signal));
+  WriteValToFd(g_shutdown_pipe_write_fd, signal);
 }
 
 // See comment in |PostCreateMainMessageLoop()|, where sigaction is called.
@@ -130,26 +134,33 @@ NOINLINE void ExitPosted() {
   sleep(UINT_MAX);
 }
 
-void ShutdownDetector::ThreadMain() {
-  base::PlatformThread::SetName("CrShutdownDetector");
-
-  int signal;
-  size_t bytes_read = 0;
-  do {
-    const ssize_t ret = HANDLE_EINTR(
-        read(shutdown_fd_, reinterpret_cast<char*>(&signal) + bytes_read,
-             sizeof(signal) - bytes_read));
-    if (ret < 0) {
+// read |sizeof(T)| raw bytes from |fd| and return the result
+template <typename T>
+[[nodiscard]] std::optional<T> ReadValFromFd(int fd) {
+  auto val = T{};
+  base::span<uint8_t> bytes = base::byte_span_from_ref(val);
+  while (!bytes.empty()) {
+    const ssize_t rv = HANDLE_EINTR(read(fd, bytes.data(), bytes.size()));
+    if (rv < 0) {
       NOTREACHED_IN_MIGRATION() << "Unexpected error: " << strerror(errno);
       ShutdownFDReadError();
-      break;
-    } else if (ret == 0) {
+      return {};
+    }
+    if (rv == 0) {
       NOTREACHED_IN_MIGRATION() << "Unexpected closure of shutdown pipe.";
       ShutdownFDClosedError();
-      break;
+      return {};
     }
-    bytes_read += ret;
-  } while (bytes_read < sizeof(signal));
+    const size_t n_bytes_read = static_cast<size_t>(rv);
+    bytes = bytes.subspan(n_bytes_read);
+  }
+  return val;
+}
+
+void ShutdownDetector::ThreadMain() {
+  base::PlatformThread::SetName("CrShutdownDetector");
+
+  const int signal = ReadValFromFd<int>(shutdown_fd_).value_or(0);
   VLOG(1) << "Handling shutdown for signal " << signal << ".";
 
   if (!task_runner_->PostTask(FROM_HERE,