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<T> 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 <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fxcrt/span_util_unittest.cpp b/core/fxcrt/span_util_unittest.cpp
index e304e91..2ceab6a 100644
--- a/core/fxcrt/span_util_unittest.cpp
+++ b/core/fxcrt/span_util_unittest.cpp
@@ -81,3 +81,11 @@
EXPECT_EQ(dst[2], 'A');
EXPECT_EQ(dst[3], 'B');
}
+
+TEST(Span, AssignOverOnePastEnd) {
+ std::vector<char> src(2, 'A');
+ pdfium::span<char> 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 e45dcec..ec9f990 100644
--- a/third_party/base/span.h
+++ b/third_party/base/span.h
@@ -209,14 +209,15 @@
// seamlessly used as a span<const T>, but not the other way around.
template <typename U, typename = internal::EnableIfLegalSpanConversion<U, T>>
constexpr span(const span<U>& 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 @@
}
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<T> data_;
size_t size_;
};