Introduce fxcrt::reinterpret_span<>()
Convert between different span types performing automatic size
adjustment. Try it in PDFium before arguing to inflict it elsewhere.
-- Introduce some bounds checks while at it.
Change-Id: I6ff7b92238b89eb3047c5f9d2cc2dd9cd7e33bf4
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/114951
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fpdfapi/edit/cpdf_stringarchivestream.cpp b/core/fpdfapi/edit/cpdf_stringarchivestream.cpp
index 48033b0..41cd8cd 100644
--- a/core/fpdfapi/edit/cpdf_stringarchivestream.cpp
+++ b/core/fpdfapi/edit/cpdf_stringarchivestream.cpp
@@ -6,6 +6,7 @@
#include <sstream>
+#include "core/fxcrt/span_util.h"
#include "third_party/base/notreached.h"
CPDF_StringArchiveStream::CPDF_StringArchiveStream(fxcrt::ostringstream* stream)
@@ -18,6 +19,7 @@
}
bool CPDF_StringArchiveStream::WriteBlock(pdfium::span<const uint8_t> buffer) {
- stream_->write(reinterpret_cast<const char*>(buffer.data()), buffer.size());
+ auto chars = fxcrt::reinterpret_span<const char>(buffer);
+ stream_->write(chars.data(), chars.size());
return true;
}
diff --git a/core/fpdfapi/parser/fpdf_parser_utility.cpp b/core/fpdfapi/parser/fpdf_parser_utility.cpp
index f2e3e36..e31131e 100644
--- a/core/fpdfapi/parser/fpdf_parser_utility.cpp
+++ b/core/fpdfapi/parser/fpdf_parser_utility.cpp
@@ -20,6 +20,7 @@
#include "core/fpdfapi/parser/fpdf_parser_decode.h"
#include "core/fxcrt/fx_extension.h"
#include "core/fxcrt/fx_stream.h"
+#include "core/fxcrt/span_util.h"
#include "third_party/base/check.h"
// Indexed by 8-bit character code, contains either:
@@ -247,8 +248,8 @@
buf << p->GetDict().Get() << "stream\r\n";
auto pAcc = pdfium::MakeRetain<CPDF_StreamAcc>(std::move(p));
pAcc->LoadAllDataRaw();
- pdfium::span<const uint8_t> span = pAcc->GetSpan();
- buf.write(reinterpret_cast<const char*>(span.data()), span.size());
+ auto span = fxcrt::reinterpret_span<const char>(pAcc->GetSpan());
+ buf.write(span.data(), span.size());
buf << "\r\nendstream";
break;
}
diff --git a/core/fpdfapi/render/cpdf_rendershading.cpp b/core/fpdfapi/render/cpdf_rendershading.cpp
index 4991d76..470a3db 100644
--- a/core/fpdfapi/render/cpdf_rendershading.cpp
+++ b/core/fpdfapi/render/cpdf_rendershading.cpp
@@ -134,7 +134,8 @@
CFX_Matrix matrix = mtObject2Bitmap.GetInverse();
for (int row = 0; row < height; row++) {
uint32_t* dib_buf =
- reinterpret_cast<uint32_t*>(pBitmap->GetWritableScanline(row).data());
+ fxcrt::reinterpret_span<uint32_t>(pBitmap->GetWritableScanline(row))
+ .data();
for (int column = 0; column < width; column++) {
CFX_PointF pos = matrix.Transform(
CFX_PointF(static_cast<float>(column), static_cast<float>(row)));
@@ -207,7 +208,8 @@
CFX_Matrix matrix = mtObject2Bitmap.GetInverse();
for (int row = 0; row < height; row++) {
uint32_t* dib_buf =
- reinterpret_cast<uint32_t*>(pBitmap->GetWritableScanline(row).data());
+ fxcrt::reinterpret_span<uint32_t>(pBitmap->GetWritableScanline(row))
+ .data();
for (int column = 0; column < width; column++) {
CFX_PointF pos = matrix.Transform(
CFX_PointF(static_cast<float>(column), static_cast<float>(row)));
@@ -288,7 +290,8 @@
std::vector<float> result_array(total_results);
for (int row = 0; row < height; ++row) {
uint32_t* dib_buf =
- reinterpret_cast<uint32_t*>(pBitmap->GetWritableScanline(row).data());
+ fxcrt::reinterpret_span<uint32_t>(pBitmap->GetWritableScanline(row))
+ .data();
for (int column = 0; column < width; column++) {
CFX_PointF pos = matrix.Transform(
CFX_PointF(static_cast<float>(column), static_cast<float>(row)));
diff --git a/core/fpdfapi/render/cpdf_rendertiling.cpp b/core/fpdfapi/render/cpdf_rendertiling.cpp
index ea83a3f..caab8f1 100644
--- a/core/fpdfapi/render/cpdf_rendertiling.cpp
+++ b/core/fpdfapi/render/cpdf_rendertiling.cpp
@@ -18,6 +18,7 @@
#include "core/fpdfapi/render/cpdf_renderoptions.h"
#include "core/fpdfapi/render/cpdf_renderstatus.h"
#include "core/fxcrt/fx_safe_types.h"
+#include "core/fxcrt/span_util.h"
#include "core/fxge/cfx_defaultrenderdevice.h"
#include "core/fxge/dib/cfx_dibitmap.h"
@@ -231,8 +232,8 @@
uint32_t* dest_buf = reinterpret_cast<uint32_t*>(
pScreen->GetWritableScanline(start_y).subspan(start_x * 4).data());
if (pPattern->colored()) {
- const auto* src_buf32 =
- reinterpret_cast<const uint32_t*>(src_buf.data());
+ const uint32_t* src_buf32 =
+ fxcrt::reinterpret_span<const uint32_t>(src_buf).data();
*dest_buf = *src_buf32;
} else {
*dest_buf = (*(src_buf.data()) << 24) | (fill_argb & 0xffffff);
diff --git a/core/fxcodec/fax/faxmodule.cpp b/core/fxcodec/fax/faxmodule.cpp
index df97129..60a7786 100644
--- a/core/fxcodec/fax/faxmodule.cpp
+++ b/core/fxcodec/fax/faxmodule.cpp
@@ -19,6 +19,7 @@
#include "core/fxcrt/data_vector.h"
#include "core/fxcrt/fx_2d_size.h"
#include "core/fxcrt/fx_memory.h"
+#include "core/fxcrt/span_util.h"
#include "core/fxge/calculate_pitch.h"
#include "third_party/base/check.h"
#include "third_party/base/check_op.h"
@@ -26,7 +27,6 @@
#include "third_party/base/numerics/safe_conversions.h"
#if BUILDFLAG(IS_WIN)
-#include "core/fxcrt/span_util.h"
#include "core/fxge/dib/cfx_dibbase.h"
#endif
@@ -584,11 +584,11 @@
}
void FaxDecoder::InvertBuffer() {
- DCHECK_EQ(m_Pitch, m_ScanlineBuf.size());
- DCHECK_EQ(m_Pitch % 4, 0u);
- uint32_t* data = reinterpret_cast<uint32_t*>(m_ScanlineBuf.data());
- for (size_t i = 0; i < m_ScanlineBuf.size() / 4; ++i)
- data[i] = ~data[i];
+ auto byte_span = pdfium::make_span(m_ScanlineBuf);
+ auto data = fxcrt::reinterpret_span<uint32_t>(byte_span);
+ for (auto& datum : data) {
+ datum = ~datum;
+ }
}
} // namespace
diff --git a/core/fxcodec/gif/cfx_gifcontext.cpp b/core/fxcodec/gif/cfx_gifcontext.cpp
index 9811759..c094f84 100644
--- a/core/fxcodec/gif/cfx_gifcontext.cpp
+++ b/core/fxcodec/gif/cfx_gifcontext.cpp
@@ -369,10 +369,10 @@
return GifDecoder::Status::kError;
bc_index_ = lsd.bc_index;
- uint32_t palette_size = palette_count * sizeof(CFX_GifPalette);
std::vector<CFX_GifPalette> palette(palette_count);
- if (!ReadAllOrNone(reinterpret_cast<uint8_t*>(palette.data()),
- palette_size)) {
+ auto bytes = pdfium::as_writable_bytes(pdfium::make_span(palette));
+ if (!ReadAllOrNone(bytes.data(),
+ pdfium::base::checked_cast<uint32_t>(bytes.size()))) {
// Roll back the read for the LSD
input_buffer_->Seek(read_marker);
return GifDecoder::Status::kUnfinished;
@@ -476,8 +476,9 @@
gif_image->local_palette_exp = gif_img_info_lf->pal_bits;
uint32_t loc_pal_count = unsigned(2 << gif_img_info_lf->pal_bits);
std::vector<CFX_GifPalette> loc_pal(loc_pal_count);
- if (!ReadAllOrNone(reinterpret_cast<uint8_t*>(loc_pal.data()),
- loc_pal_count * sizeof(CFX_GifPalette))) {
+ auto bytes = pdfium::as_writable_bytes(pdfium::make_span(loc_pal));
+ if (!ReadAllOrNone(bytes.data(),
+ pdfium::base::checked_cast<uint32_t>(bytes.size()))) {
input_buffer_->Seek(read_marker);
return GifDecoder::Status::kUnfinished;
}
diff --git a/core/fxcrt/span_util.h b/core/fxcrt/span_util.h
index 2a34980..3b29f5c 100644
--- a/core/fxcrt/span_util.h
+++ b/core/fxcrt/span_util.h
@@ -5,6 +5,8 @@
#ifndef CORE_FXCRT_SPAN_UTIL_H_
#define CORE_FXCRT_SPAN_UTIL_H_
+#include <stdint.h>
+
#include "core/fxcrt/fx_memcpy_wrappers.h"
#include "third_party/base/check_op.h"
#include "third_party/base/containers/span.h"
@@ -41,6 +43,16 @@
FXSYS_memset(dst.data(), 0, dst.size_bytes());
}
+template <typename T,
+ typename U,
+ typename = typename std::enable_if_t<std::is_const_v<T> ||
+ !std::is_const_v<U>>>
+inline pdfium::span<T> reinterpret_span(pdfium::span<U> s) noexcept {
+ CHECK_EQ(s.size_bytes() % sizeof(T), 0u);
+ CHECK_EQ(reinterpret_cast<uintptr_t>(s.data()) % alignof(T), 0u);
+ return {reinterpret_cast<T*>(s.data()), s.size_bytes() / sizeof(T)};
+}
+
} // namespace fxcrt
#endif // CORE_FXCRT_SPAN_UTIL_H_
diff --git a/core/fxcrt/span_util_unittest.cpp b/core/fxcrt/span_util_unittest.cpp
index 5718ed8..577e2f7 100644
--- a/core/fxcrt/span_util_unittest.cpp
+++ b/core/fxcrt/span_util_unittest.cpp
@@ -89,3 +89,33 @@
span = pdfium::make_span(src);
EXPECT_EQ(span.size(), 2u);
}
+
+TEST(ReinterpretSpan, Empty) {
+ pdfium::span<uint8_t> empty;
+ pdfium::span<uint32_t> converted = fxcrt::reinterpret_span<uint32_t>(empty);
+ EXPECT_EQ(converted.data(), nullptr);
+ EXPECT_EQ(converted.size(), 0u);
+}
+
+TEST(ReinterpretSpan, LegalConversions) {
+ uint8_t aaaabbbb[8] = {0x61, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62, 0x62};
+ pdfium::span<uint8_t> original = pdfium::make_span(aaaabbbb);
+ pdfium::span<uint32_t> converted =
+ fxcrt::reinterpret_span<uint32_t>(original);
+ ASSERT_NE(converted.data(), nullptr);
+ ASSERT_EQ(converted.size(), 2u);
+ EXPECT_EQ(converted[0], 0x61616161u);
+ EXPECT_EQ(converted[1], 0x62626262u);
+}
+
+TEST(ReinterpretSpan, BadLength) {
+ uint8_t ab[2] = {0x61, 0x62};
+ EXPECT_DEATH(fxcrt::reinterpret_span<uint32_t>(pdfium::make_span(ab)), "");
+}
+
+TEST(ReinterpretSpan, BadAlignment) {
+ uint8_t abcabc[6] = {0x61, 0x62, 0x63, 0x61, 0x62, 0x63};
+ EXPECT_DEATH(fxcrt::reinterpret_span<uint32_t>(
+ pdfium::make_span(abcabc).subspan(1, 4)),
+ "");
+}
diff --git a/core/fxge/dib/cfx_dibbase.cpp b/core/fxge/dib/cfx_dibbase.cpp
index f80c19e..cd00ede 100644
--- a/core/fxge/dib/cfx_dibbase.cpp
+++ b/core/fxge/dib/cfx_dibbase.cpp
@@ -659,13 +659,15 @@
int right_shift = 32 - left_shift;
int dword_count = pNewBitmap->m_Pitch / 4;
for (int row = rect.top; row < rect.bottom; ++row) {
+ auto src_span = fxcrt::reinterpret_span<const uint32_t>(GetScanline(row));
+ auto dst_span = fxcrt::reinterpret_span<uint32_t>(
+ pNewBitmap->GetWritableScanline(row - rect.top));
+ // Bounds check for free with first/subspan.
const uint32_t* src_scan =
- reinterpret_cast<const uint32_t*>(GetScanline(row).data()) +
- rect.left / 32;
- uint32_t* dest_scan = reinterpret_cast<uint32_t*>(
- pNewBitmap->GetWritableScanline(row - rect.top).data());
+ src_span.subspan(rect.left / 32, dword_count + 1).data();
+ uint32_t* dst_scan = dst_span.first(dword_count).data();
for (int i = 0; i < dword_count; ++i) {
- dest_scan[i] =
+ dst_scan[i] =
(src_scan[i] << left_shift) | (src_scan[i + 1] >> right_shift);
}
}
@@ -1011,8 +1013,9 @@
uint8_t* dest_scan = dest_span.subspan(dest_offset).data();
if (nBytes == 4) {
const uint32_t* src_scan =
- reinterpret_cast<const uint32_t*>(GetScanline(row).data()) +
- col_start;
+ fxcrt::reinterpret_span<const uint32_t>(GetScanline(row))
+ .subspan(col_start)
+ .data();
for (int col = col_start; col < col_end; ++col) {
uint32_t* dest_scan32 = reinterpret_cast<uint32_t*>(dest_scan);
*dest_scan32 = *src_scan++;
diff --git a/core/fxge/win32/cfx_psrenderer.cpp b/core/fxge/win32/cfx_psrenderer.cpp
index ff3bd9f..cb9e069 100644
--- a/core/fxge/win32/cfx_psrenderer.cpp
+++ b/core/fxge/win32/cfx_psrenderer.cpp
@@ -904,7 +904,8 @@
DataVector<uint8_t> encoded_data = m_pEncoderIface->pA85EncodeFunc(data);
pdfium::span<const uint8_t> result =
encoded_data.empty() ? data : encoded_data;
- m_Output.write(reinterpret_cast<const char*>(result.data()), result.size());
+ auto chars = fxcrt::reinterpret_span<const char>(result);
+ m_Output.write(chars.data(), chars.size());
}
void CFX_PSRenderer::WriteStream(fxcrt::ostringstream& stream) {
diff --git a/testing/string_write_stream.cpp b/testing/string_write_stream.cpp
index 1a99d9a..feb11f9 100644
--- a/testing/string_write_stream.cpp
+++ b/testing/string_write_stream.cpp
@@ -5,6 +5,7 @@
#include "testing/string_write_stream.h"
#include "core/fxcrt/bytestring.h"
+#include "core/fxcrt/span_util.h"
#include "core/fxcrt/widestring.h"
StringWriteStream::StringWriteStream() = default;
@@ -12,6 +13,7 @@
StringWriteStream::~StringWriteStream() = default;
bool StringWriteStream::WriteBlock(pdfium::span<const uint8_t> buffer) {
- stream_.write(reinterpret_cast<const char*>(buffer.data()), buffer.size());
+ auto chars = fxcrt::reinterpret_span<const char>(buffer);
+ stream_.write(chars.data(), chars.size());
return true;
}
diff --git a/xfa/fgas/graphics/cfgas_gegraphics.cpp b/xfa/fgas/graphics/cfgas_gegraphics.cpp
index 5b5da61..082b75a 100644
--- a/xfa/fgas/graphics/cfgas_gegraphics.cpp
+++ b/xfa/fgas/graphics/cfgas_gegraphics.cpp
@@ -299,7 +299,8 @@
float axis_len_square = (x_span * x_span) + (y_span * y_span);
for (int32_t row = 0; row < height; row++) {
uint32_t* dib_buf =
- reinterpret_cast<uint32_t*>(bmp->GetWritableScanline(row).data());
+ fxcrt::reinterpret_span<uint32_t>(bmp->GetWritableScanline(row))
+ .data();
for (int32_t column = 0; column < width; column++) {
float scale = 0.0f;
if (axis_len_square) {
@@ -333,7 +334,8 @@
((start_r - end_r) * (start_r - end_r));
for (int32_t row = 0; row < height; row++) {
uint32_t* dib_buf =
- reinterpret_cast<uint32_t*>(bmp->GetWritableScanline(row).data());
+ fxcrt::reinterpret_span<uint32_t>(bmp->GetWritableScanline(row))
+ .data();
for (int32_t column = 0; column < width; column++) {
float x = (float)(column);
float y = (float)(row);