Introduce bounds-checked memcpy() et al. for span<>

An attempt to eliminate memcpy() from the code base while still
calling memcpy under the covers.

Convert a few callers to demonstrate usage.

Change-Id: Id85ad1fa3cf67f585506828d880ba10b1bc992e4
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/82631
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfapi/parser/cpdf_stream.cpp b/core/fpdfapi/parser/cpdf_stream.cpp
index 356d006..c655b95 100644
--- a/core/fpdfapi/parser/cpdf_stream.cpp
+++ b/core/fpdfapi/parser/cpdf_stream.cpp
@@ -18,6 +18,7 @@
 #include "core/fpdfapi/parser/cpdf_stream_acc.h"
 #include "core/fpdfapi/parser/fpdf_parser_decode.h"
 #include "core/fxcrt/fx_stream.h"
+#include "core/fxcrt/span_util.h"
 #include "third_party/base/containers/contains.h"
 #include "third_party/base/numerics/safe_conversions.h"
 
@@ -131,7 +132,8 @@
   std::unique_ptr<uint8_t, FxFreeDeleter> data_copy;
   if (!pData.empty()) {
     data_copy.reset(FX_AllocUninit(uint8_t, pData.size()));
-    memcpy(data_copy.get(), pData.data(), pData.size());
+    auto copy_span = pdfium::make_span(data_copy.get(), pData.size());
+    fxcrt::spancpy(copy_span, pData);
   }
   TakeData(std::move(data_copy), pData.size());
 }
diff --git a/core/fpdfapi/parser/fpdf_parser_decode.cpp b/core/fpdfapi/parser/fpdf_parser_decode.cpp
index 4326ddf..4f63dd1 100644
--- a/core/fpdfapi/parser/fpdf_parser_decode.cpp
+++ b/core/fpdfapi/parser/fpdf_parser_decode.cpp
@@ -23,6 +23,7 @@
 #include "core/fxcodec/scanlinedecoder.h"
 #include "core/fxcrt/fx_extension.h"
 #include "core/fxcrt/fx_safe_types.h"
+#include "core/fxcrt/span_util.h"
 #include "third_party/base/check.h"
 #include "third_party/base/containers/contains.h"
 
@@ -273,18 +274,17 @@
       if (buf_left < copy_len) {
         uint32_t delta = copy_len - buf_left;
         copy_len = buf_left;
-        memset(&dest_span[dest_count + copy_len], '\0', delta);
+        fxcrt::spanclr(dest_span.subspan(dest_count + copy_len, delta));
       }
       auto copy_span = src_span.subspan(i + 1, copy_len);
-      memcpy(&dest_span[dest_count], copy_span.data(), copy_span.size());
+      fxcrt::spancpy(dest_span.subspan(dest_count), copy_span);
       dest_count += src_span[i] + 1;
       i += src_span[i] + 2;
     } else {
-      int fill = 0;
-      if (i < src_span.size() - 1)
-        fill = src_span[i + 1];
-      memset(&dest_span[dest_count], fill, 257 - src_span[i]);
-      dest_count += 257 - src_span[i];
+      const uint8_t fill = i < src_span.size() - 1 ? src_span[i + 1] : 0;
+      const size_t fill_size = 257 - src_span[i];
+      fxcrt::spanset(dest_span.subspan(dest_count, fill_size), fill);
+      dest_count += fill_size;
       i += 2;
     }
   }
diff --git a/core/fxcodec/basic/basicmodule.cpp b/core/fxcodec/basic/basicmodule.cpp
index b3abc99..6cb8eb3 100644
--- a/core/fxcodec/basic/basicmodule.cpp
+++ b/core/fxcodec/basic/basicmodule.cpp
@@ -9,7 +9,9 @@
 #include <vector>
 
 #include "core/fxcodec/scanlinedecoder.h"
+#include "core/fxcrt/fx_memory_wrappers.h"
 #include "core/fxcrt/fx_safe_types.h"
+#include "core/fxcrt/span_util.h"
 #include "third_party/base/check.h"
 
 namespace fxcodec {
@@ -107,7 +109,7 @@
 }
 
 bool RLScanlineDecoder::v_Rewind() {
-  memset(m_Scanline.data(), 0, m_Pitch);
+  fxcrt::spanclr(pdfium::make_span(m_Scanline));
   m_SrcOffset = 0;
   m_bEOD = false;
   m_Operator = 0;
@@ -120,9 +122,10 @@
   } else if (m_bEOD) {
     return nullptr;
   }
-  memset(m_Scanline.data(), 0, m_Pitch);
   uint32_t col_pos = 0;
   bool eol = false;
+  auto scan_span = pdfium::make_span(m_Scanline);
+  fxcrt::spanclr(scan_span);
   while (m_SrcOffset < m_SrcBuf.size() && !eol) {
     if (m_Operator < 128) {
       uint32_t copy_len = m_Operator + 1;
@@ -135,7 +138,7 @@
         m_bEOD = true;
       }
       auto copy_span = m_SrcBuf.subspan(m_SrcOffset, copy_len);
-      memcpy(m_Scanline.data() + col_pos, copy_span.data(), copy_span.size());
+      fxcrt::spancpy(scan_span.subspan(col_pos), copy_span);
       col_pos += copy_len;
       UpdateOperator((uint8_t)copy_len);
     } else if (m_Operator > 128) {
@@ -148,7 +151,7 @@
         duplicate_len = m_dwLineBytes - col_pos;
         eol = true;
       }
-      memset(m_Scanline.data() + col_pos, fill, duplicate_len);
+      fxcrt::spanset(scan_span.subspan(col_pos, duplicate_len), fill);
       col_pos += duplicate_len;
       UpdateOperator((uint8_t)duplicate_len);
     } else {
diff --git a/core/fxcrt/BUILD.gn b/core/fxcrt/BUILD.gn
index cdbf119..6b20ced 100644
--- a/core/fxcrt/BUILD.gn
+++ b/core/fxcrt/BUILD.gn
@@ -64,6 +64,7 @@
     "retained_tree_node.h",
     "scoped_set_insertion.h",
     "shared_copy_on_write.h",
+    "span_util.h",
     "stl_util.h",
     "string_data_template.cpp",
     "string_data_template.h",
diff --git a/core/fxcrt/span_util.h b/core/fxcrt/span_util.h
new file mode 100644
index 0000000..bbf5ec5
--- /dev/null
+++ b/core/fxcrt/span_util.h
@@ -0,0 +1,67 @@
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CORE_FXCRT_SPAN_UTIL_H_
+#define CORE_FXCRT_SPAN_UTIL_H_
+
+#include <vector>
+
+#include "third_party/base/check_op.h"
+#include "third_party/base/span.h"
+
+namespace fxcrt {
+
+// NOTE: there are separate versions fot span<T> and span<const T>
+// source arguments because type deduction seems to have trouble with
+// automatically converting span<T> to span<const T>.
+
+// Bounds-checked copies from spans into spans.
+template <typename T>
+void spancpy(pdfium::span<T> dst, pdfium::span<const T> src) {
+  CHECK_GE(dst.size(), src.size());
+  memcpy(dst.data(), src.data(), src.size_bytes());
+}
+
+template <typename T>
+void spancpy(pdfium::span<T> dst, pdfium::span<T> src) {
+  CHECK_GE(dst.size(), src.size());
+  memcpy(dst.data(), src.data(), src.size_bytes());
+}
+
+// Bounds-checked moves from spans into spans.
+template <typename T>
+void spanmove(pdfium::span<T> dst, pdfium::span<T> src) {
+  CHECK_GE(dst.size(), src.size());
+  memmove(dst.data(), src.data(), src.size_bytes());
+}
+
+template <typename T>
+void spanmove(pdfium::span<T> dst, pdfium::span<const T> src) {
+  CHECK_GE(dst.size(), src.size());
+  memmove(dst.data(), src.data(), src.size_bytes());
+}
+
+// Bounds-checked sets into spans.
+template <typename T>
+void spanset(pdfium::span<T> dst, uint8_t val) {
+  memset(dst.data(), val, dst.size_bytes());
+}
+
+// Bounds-checked zeroing of spans.
+template <typename T>
+void spanclr(pdfium::span<T> dst) {
+  memset(dst.data(), 0, dst.size_bytes());
+}
+
+// Extracting subspans from arrays.
+template <typename T, typename A>
+pdfium::span<T> Subspan(std::vector<T, A>& vec,
+                        size_t start,
+                        size_t count = -1) {
+  return pdfium::make_span(vec).subspan(start, count);
+}
+
+}  // namespace fxcrt
+
+#endif  // CORE_FXCRT_SPAN_UTIL_H_