From 8479a083aa9f0e7418c00a1a0afc9fa485154023 Mon Sep 17 00:00:00 2001 From: Tom Sepez Date: Mon, 29 Aug 2022 20:07:44 +0000 Subject: [PATCH] Fix bad probe on span assignment operator. Empty spans with data pointers one past the end of an object are allowed, but we can't allow UnownedPtr to probe for validity of this location during an assignment for these spans. See e.g. https://pdfium-review.googlesource.com/c/pdfium/+/96971 for an example of how this goes wrong. Change-Id: I7ab60800a4d1584aeeec8343362337cb6c137672 Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/97031 Reviewed-by: Lei Zhang Commit-Queue: Tom Sepez --- core/fxcrt/span_util_unittest.cpp | 8 ++++++++ third_party/base/span.h | 20 ++++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/core/fxcrt/span_util_unittest.cpp b/core/fxcrt/span_util_unittest.cpp index e304e914d3..2ceab6a976 100644 --- a/core/fxcrt/span_util_unittest.cpp +++ b/core/fxcrt/span_util_unittest.cpp @@ -81,3 +81,11 @@ TEST(Spanmove, FitsWithin) { EXPECT_EQ(dst[2], 'A'); EXPECT_EQ(dst[3], 'B'); } + +TEST(Span, AssignOverOnePastEnd) { + std::vector src(2, 'A'); + pdfium::span span = pdfium::make_span(src); + span = span.subspan(2); + span = pdfium::make_span(src); + EXPECT_EQ(span.size(), 2u); +} diff --git a/third_party/base/span.h b/third_party/base/span.h index e45dcec082..ec9f9903f8 100644 --- a/third_party/base/span.h +++ b/third_party/base/span.h @@ -209,14 +209,15 @@ class span { // seamlessly used as a span, but not the other way around. template > constexpr span(const span& other) : span(other.data(), other.size()) {} - span& operator=(const span& other) noexcept = default; - ~span() noexcept { - if (!size_) { - // Empty spans might point to byte N+1 of a N-byte object, legal for - // C pointers but not UnownedPtrs. - data_.ReleaseBadPointer(); + span& operator=(const span& other) noexcept { + if (this != &other) { + ReleaseEmptySpan(); + data_ = other.data_; + size_ = other.size_; } + return *this; } + ~span() noexcept { ReleaseEmptySpan(); } // [span.sub], span subviews const span first(size_t count) const { @@ -281,6 +282,13 @@ class span { } private: + void ReleaseEmptySpan() noexcept { + // Empty spans might point to byte N+1 of a N-byte object, legal for + // C pointers but not UnownedPtrs. + if (!size_) + data_.ReleaseBadPointer(); + } + UnownedPtr data_; size_t size_; };