Prevent size_t overflow in StrAppend and AppendPieces on 32-bit platforms PiperOrigin-RevId: 946021594 Change-Id: Ib377ddc3d9aaf13ec1d7f73ad063e8e4e1e0d842
diff --git a/absl/strings/str_cat.cc b/absl/strings/str_cat.cc index 546b8ae..b79078d 100644 --- a/absl/strings/str_cat.cc +++ b/absl/strings/str_cat.cc
@@ -26,6 +26,8 @@ #include "absl/base/config.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/nullability.h" +#include "absl/base/optimization.h" +#include "absl/base/throw_delegate.h" #include "absl/strings/internal/append_and_overwrite.h" #include "absl/strings/resize_and_overwrite.h" #include "absl/strings/string_view.h" @@ -53,6 +55,26 @@ return after; } +// Safely adds size_t values, throwing std::length_error if overflow occurs. +inline size_t SafeAdd(size_t a, size_t b) { + const uint64_t sum = static_cast<uint64_t>(a) + b; + if (ABSL_PREDICT_FALSE(sum > (std::numeric_limits<size_t>::max)())) { + ThrowStdLengthError("absl string append length overflow"); + } + return static_cast<size_t>(sum); +} + +inline size_t SafeAdd(std::initializer_list<size_t> sizes) { + uint64_t sum = 0; + for (size_t size : sizes) { + sum += size; + } + if (ABSL_PREDICT_FALSE(sum > (std::numeric_limits<size_t>::max)())) { + ThrowStdLengthError("absl string append length overflow"); + } + return static_cast<size_t>(sum); +} + } // namespace std::string StrCat(const AlphaNum& a, const AlphaNum& b) { @@ -163,7 +185,7 @@ size_t to_append = 0; for (absl::string_view piece : pieces) { ASSERT_NO_OVERLAP(*dest, piece); - to_append += piece.size(); + to_append = SafeAdd(to_append, piece.size()); } StringAppendAndOverwrite(*dest, to_append, [&pieces](char* const buf, size_t buf_size) { @@ -198,7 +220,8 @@ ASSERT_NO_OVERLAP(*dest, a); ASSERT_NO_OVERLAP(*dest, b); strings_internal::StringAppendAndOverwrite( - *dest, a.size() + b.size(), [&a, &b](char* const buf, size_t buf_size) { + *dest, SafeAdd(a.size(), b.size()), + [&a, &b](char* const buf, size_t buf_size) { char* out = buf; out = Append(out, a); out = Append(out, b); @@ -213,7 +236,7 @@ ASSERT_NO_OVERLAP(*dest, b); ASSERT_NO_OVERLAP(*dest, c); strings_internal::StringAppendAndOverwrite( - *dest, a.size() + b.size() + c.size(), + *dest, SafeAdd({a.size(), b.size(), c.size()}), [&a, &b, &c](char* const buf, size_t buf_size) { char* out = buf; out = Append(out, a); @@ -231,7 +254,7 @@ ASSERT_NO_OVERLAP(*dest, c); ASSERT_NO_OVERLAP(*dest, d); strings_internal::StringAppendAndOverwrite( - *dest, a.size() + b.size() + c.size() + d.size(), + *dest, SafeAdd({a.size(), b.size(), c.size(), d.size()}), [&a, &b, &c, &d](char* const buf, size_t buf_size) { char* out = buf; out = Append(out, a);