Repository: nodejs/node
Pull request: src: fix reading empty string views in Blob[De]serializer

The string writing/reading was intended for debugging info in snapshot, which had a CHECK_GT(length, 0) check, it then got repurposed for SEA resource writing/reading and turned into a helper for string views, but was not updated to handle empty views, causing occasional crash in the CI when the read is protected. This patch fixes it.

Fixes: https://github.com/nodejs/node/issues/50740
<!--
Before submitting a pull request, please read:

- the CONTRIBUTING guide at https://github.com/nodejs/node/blob/HEAD/CONTRIBUTING.md
- the commit message formatting guidelines at
  https://github.com/nodejs/node/blob/HEAD/doc/contributing/pull-requests.md#commit-message-guidelines

For code changes:
1. Include tests for any bug fixes or new features.
2. Update documentation if relevant.
3. Ensure that `make -j4 test` (UNIX), or `vcbuild test` (Windows) passes.

If you believe this PR should be highlighted in the Node.js CHANGELOG
please add the `notable-change` label.

Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
    have the right to submit it under the open source license
    indicated in the file; or

(b) The contribution is based upon previous work that, to the best
    of my knowledge, is covered under an appropriate open source
    license and I have the right under that license to submit that
    work with modifications, whether created in whole or in part
    by me, under the same open source license (unless I am
    permitted to submit under a different license), as indicated
    in the file; or

(c) The contribution was provided directly to me by some other
    person who certified (a), (b) or (c) and I have not modified
    it.

(d) I understand and agree that this project and the contribution
    are public and that a record of the contribution (including all
    personal information I submit with it, including my sign-off) is
    maintained indefinitely and may be redistributed consistent with
    this project or the open source license(s) involved.
-->


Changed files:
filename: src/api/environment.cc
patch: @@ -553,7 +553,9 @@ MaybeLocal<Value> LoadEnvironment(Environment* env,
 MaybeLocal<Value> LoadEnvironment(Environment* env,
                                   std::string_view main_script_source_utf8,
                                   EmbedderPreloadCallback preload) {
-  CHECK_NOT_NULL(main_script_source_utf8.data());
+  // It could be empty when it's used by SEA to load an empty script.
+  CHECK_IMPLIES(main_script_source_utf8.size() > 0,
+                main_script_source_utf8.data());
   return LoadEnvironment(
       env,
       [&](const StartExecutionCallbackInfo& info) -> MaybeLocal<Value> {

filename: src/blob_serializer_deserializer-inl.h
patch: @@ -139,6 +139,11 @@ std::string_view BlobDeserializer<Impl>::ReadStringView(StringLogMode mode) {
   size_t length = ReadArithmetic<size_t>();
   Debug("ReadStringView(), length=%zu: ", length);
 
+  if (length == 0) {
+    Debug("ReadStringView() read an empty view\n");
+    return std::string_view();
+  }
+
   std::string_view result(sink.data() + read_total, length);
   Debug("%p, read %zu bytes", result.data(), result.size());
   if (mode == StringLogMode::kAddressAndContent) {
@@ -269,6 +274,10 @@ size_t BlobSerializer<Impl>::WriteStringView(std::string_view data,
   size_t written_total = WriteArithmetic<size_t>(data.size());
 
   size_t length = data.size();
+  if (length == 0) {
+    Debug("WriteStringView() wrote an empty view\n");
+    return written_total;
+  }
   sink.insert(sink.end(), data.data(), data.data() + length);
   written_total += length;