Skip to content

Commit

Permalink
Add additional checks for size_t overflows
Browse files Browse the repository at this point in the history
This change mainly affects 32-bit platforms. Similar to
4618865, check for size_t overflow
in all places where string result sizes are precomputed before allocation.

PiperOrigin-RevId: 615792028
Change-Id: I71c774c5ef2c2978bd812c70e9bab36d266b7c90
  • Loading branch information
derekmauro authored and copybara-github committed Mar 14, 2024
1 parent 2f05910 commit 74df697
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 12 deletions.
7 changes: 5 additions & 2 deletions absl/strings/internal/escaping.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -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
Expand Down Expand Up @@ -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;
}

Expand Down
12 changes: 10 additions & 2 deletions absl/strings/internal/str_join_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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();
Expand Down
45 changes: 37 additions & 8 deletions absl/strings/str_cat.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -32,7 +34,6 @@
namespace absl {
ABSL_NAMESPACE_BEGIN


// ----------------------------------------------------------------------
// StrCat()
// This merges the given strings or integers, with no delimiter. This
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions absl/strings/substitute.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <limits>
#include <string>

#include "absl/base/config.h"
Expand Down Expand Up @@ -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];
Expand Down

0 comments on commit 74df697

Please sign in to comment.