Commit 74df6975 by Derek Mauro Committed by Copybara-Service

Add additional checks for size_t overflows

This change mainly affects 32-bit platforms. Similar to
4618865c, check for size_t overflow
in all places where string result sizes are precomputed before allocation.

PiperOrigin-RevId: 615792028
Change-Id: I71c774c5ef2c2978bd812c70e9bab36d266b7c90
parent 2f059101
......@@ -14,6 +14,8 @@
#include "absl/strings/internal/escaping.h"
#include <limits>
#include "absl/base/internal/endian.h"
#include "absl/base/internal/raw_logging.h"
......@@ -31,12 +33,14 @@ ABSL_CONST_INIT const char kBase64Chars[] =
ABSL_CONST_INIT const char kWebSafeBase64Chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
size_t CalculateBase64EscapedLenInternal(size_t input_len, bool do_padding) {
// Base64 encodes three bytes of input at a time. If the input is not
// divisible by three, we pad as appropriate.
//
// Base64 encodes each three bytes of input into four bytes of output.
constexpr size_t kMaxSize = (std::numeric_limits<size_t>::max() - 1) / 4 * 3;
ABSL_INTERNAL_CHECK(input_len <= kMaxSize,
"CalculateBase64EscapedLenInternal() overflow");
size_t len = (input_len / 3) * 4;
// Since all base 64 input is an integral number of octets, only the following
......@@ -66,7 +70,6 @@ size_t CalculateBase64EscapedLenInternal(size_t input_len, bool do_padding) {
}
}
assert(len >= input_len); // make sure we didn't overflow
return len;
}
......
......@@ -31,13 +31,16 @@
#ifndef ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_
#define ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_
#include <cstdint>
#include <cstring>
#include <iterator>
#include <limits>
#include <memory>
#include <string>
#include <type_traits>
#include <utility>
#include "absl/base/internal/raw_logging.h"
#include "absl/strings/internal/ostringstream.h"
#include "absl/strings/internal/resize_uninitialized.h"
#include "absl/strings/str_cat.h"
......@@ -230,14 +233,19 @@ std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s,
if (start != end) {
// Sums size
auto&& start_value = *start;
size_t result_size = start_value.size();
// Use uint64_t to prevent size_t overflow. We assume it is not possible for
// in memory strings to overflow a uint64_t.
uint64_t result_size = start_value.size();
for (Iterator it = start; ++it != end;) {
result_size += s.size();
result_size += (*it).size();
}
if (result_size > 0) {
STLStringResizeUninitialized(&result, result_size);
constexpr uint64_t kMaxSize =
uint64_t{(std::numeric_limits<size_t>::max)()};
ABSL_INTERNAL_CHECK(result_size <= kMaxSize, "size_t overflow");
STLStringResizeUninitialized(&result, static_cast<size_t>(result_size));
// Joins strings
char* result_buf = &*result.begin();
......
......@@ -20,10 +20,12 @@
#include <cstdint>
#include <cstring>
#include <initializer_list>
#include <limits>
#include <string>
#include <type_traits>
#include "absl/base/config.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/nullability.h"
#include "absl/strings/internal/resize_uninitialized.h"
#include "absl/strings/numbers.h"
......@@ -32,7 +34,6 @@
namespace absl {
ABSL_NAMESPACE_BEGIN
// ----------------------------------------------------------------------
// StrCat()
// This merges the given strings or integers, with no delimiter. This
......@@ -57,8 +58,14 @@ absl::Nonnull<char*> Append(absl::Nonnull<char*> out, const AlphaNum& x) {
std::string StrCat(const AlphaNum& a, const AlphaNum& b) {
std::string result;
absl::strings_internal::STLStringResizeUninitialized(&result,
a.size() + b.size());
// Use uint64_t to prevent size_t overflow. We assume it is not possible for
// in memory strings to overflow a uint64_t.
constexpr uint64_t kMaxSize = uint64_t{std::numeric_limits<size_t>::max()};
const uint64_t result_size =
static_cast<uint64_t>(a.size()) + static_cast<uint64_t>(b.size());
ABSL_INTERNAL_CHECK(result_size <= kMaxSize, "size_t overflow");
absl::strings_internal::STLStringResizeUninitialized(
&result, static_cast<size_t>(result_size));
char* const begin = &result[0];
char* out = begin;
out = Append(out, a);
......@@ -69,8 +76,15 @@ std::string StrCat(const AlphaNum& a, const AlphaNum& b) {
std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c) {
std::string result;
// Use uint64_t to prevent size_t overflow. We assume it is not possible for
// in memory strings to overflow a uint64_t.
constexpr uint64_t kMaxSize = uint64_t{std::numeric_limits<size_t>::max()};
const uint64_t result_size = static_cast<uint64_t>(a.size()) +
static_cast<uint64_t>(b.size()) +
static_cast<uint64_t>(c.size());
ABSL_INTERNAL_CHECK(result_size <= kMaxSize, "size_t overflow");
strings_internal::STLStringResizeUninitialized(
&result, a.size() + b.size() + c.size());
&result, static_cast<size_t>(result_size));
char* const begin = &result[0];
char* out = begin;
out = Append(out, a);
......@@ -83,8 +97,16 @@ std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c) {
std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c,
const AlphaNum& d) {
std::string result;
// Use uint64_t to prevent size_t overflow. We assume it is not possible for
// in memory strings to overflow a uint64_t.
constexpr uint64_t kMaxSize = uint64_t{std::numeric_limits<size_t>::max()};
const uint64_t result_size = static_cast<uint64_t>(a.size()) +
static_cast<uint64_t>(b.size()) +
static_cast<uint64_t>(c.size()) +
static_cast<uint64_t>(d.size());
ABSL_INTERNAL_CHECK(result_size <= kMaxSize, "size_t overflow");
strings_internal::STLStringResizeUninitialized(
&result, a.size() + b.size() + c.size() + d.size());
&result, static_cast<size_t>(result_size));
char* const begin = &result[0];
char* out = begin;
out = Append(out, a);
......@@ -224,9 +246,16 @@ void SingleArgStrAppend(std::string& str, unsigned long long x) {
std::string CatPieces(std::initializer_list<absl::string_view> pieces) {
std::string result;
size_t total_size = 0;
for (absl::string_view piece : pieces) total_size += piece.size();
strings_internal::STLStringResizeUninitialized(&result, total_size);
// Use uint64_t to prevent size_t overflow. We assume it is not possible for
// in memory strings to overflow a uint64_t.
constexpr uint64_t kMaxSize = uint64_t{std::numeric_limits<size_t>::max()};
uint64_t total_size = 0;
for (absl::string_view piece : pieces) {
total_size += piece.size();
}
ABSL_INTERNAL_CHECK(total_size <= kMaxSize, "size_t overflow");
strings_internal::STLStringResizeUninitialized(
&result, static_cast<size_t>(total_size));
char* const begin = &result[0];
char* out = begin;
......
......@@ -18,6 +18,7 @@
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <limits>
#include <string>
#include "absl/base/config.h"
......@@ -84,6 +85,9 @@ void SubstituteAndAppendArray(
// Build the string.
size_t original_size = output->size();
ABSL_INTERNAL_CHECK(
size <= std::numeric_limits<size_t>::max() - original_size,
"size_t overflow");
strings_internal::STLStringResizeUninitializedAmortized(output,
original_size + size);
char* target = &(*output)[original_size];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment