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_