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 @@ ...@@ -14,6 +14,8 @@
#include "absl/strings/internal/escaping.h" #include "absl/strings/internal/escaping.h"
#include <limits>
#include "absl/base/internal/endian.h" #include "absl/base/internal/endian.h"
#include "absl/base/internal/raw_logging.h" #include "absl/base/internal/raw_logging.h"
...@@ -31,12 +33,14 @@ ABSL_CONST_INIT const char kBase64Chars[] = ...@@ -31,12 +33,14 @@ ABSL_CONST_INIT const char kBase64Chars[] =
ABSL_CONST_INIT const char kWebSafeBase64Chars[] = ABSL_CONST_INIT const char kWebSafeBase64Chars[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
size_t CalculateBase64EscapedLenInternal(size_t input_len, bool do_padding) { size_t CalculateBase64EscapedLenInternal(size_t input_len, bool do_padding) {
// Base64 encodes three bytes of input at a time. If the input is not // Base64 encodes three bytes of input at a time. If the input is not
// divisible by three, we pad as appropriate. // divisible by three, we pad as appropriate.
// //
// Base64 encodes each three bytes of input into four bytes of output. // 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; size_t len = (input_len / 3) * 4;
// Since all base 64 input is an integral number of octets, only the following // 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) { ...@@ -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; return len;
} }
......
...@@ -31,13 +31,16 @@ ...@@ -31,13 +31,16 @@
#ifndef ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_ #ifndef ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_
#define ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_ #define ABSL_STRINGS_INTERNAL_STR_JOIN_INTERNAL_H_
#include <cstdint>
#include <cstring> #include <cstring>
#include <iterator> #include <iterator>
#include <limits>
#include <memory> #include <memory>
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include "absl/base/internal/raw_logging.h"
#include "absl/strings/internal/ostringstream.h" #include "absl/strings/internal/ostringstream.h"
#include "absl/strings/internal/resize_uninitialized.h" #include "absl/strings/internal/resize_uninitialized.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
...@@ -230,14 +233,19 @@ std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s, ...@@ -230,14 +233,19 @@ std::string JoinAlgorithm(Iterator start, Iterator end, absl::string_view s,
if (start != end) { if (start != end) {
// Sums size // Sums size
auto&& start_value = *start; 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;) { for (Iterator it = start; ++it != end;) {
result_size += s.size(); result_size += s.size();
result_size += (*it).size(); result_size += (*it).size();
} }
if (result_size > 0) { 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 // Joins strings
char* result_buf = &*result.begin(); char* result_buf = &*result.begin();
......
...@@ -20,10 +20,12 @@ ...@@ -20,10 +20,12 @@
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
#include <initializer_list> #include <initializer_list>
#include <limits>
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include "absl/base/config.h" #include "absl/base/config.h"
#include "absl/base/internal/raw_logging.h"
#include "absl/base/nullability.h" #include "absl/base/nullability.h"
#include "absl/strings/internal/resize_uninitialized.h" #include "absl/strings/internal/resize_uninitialized.h"
#include "absl/strings/numbers.h" #include "absl/strings/numbers.h"
...@@ -32,7 +34,6 @@ ...@@ -32,7 +34,6 @@
namespace absl { namespace absl {
ABSL_NAMESPACE_BEGIN ABSL_NAMESPACE_BEGIN
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// StrCat() // StrCat()
// This merges the given strings or integers, with no delimiter. This // 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) { ...@@ -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 StrCat(const AlphaNum& a, const AlphaNum& b) {
std::string result; std::string result;
absl::strings_internal::STLStringResizeUninitialized(&result, // Use uint64_t to prevent size_t overflow. We assume it is not possible for
a.size() + b.size()); // 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* const begin = &result[0];
char* out = begin; char* out = begin;
out = Append(out, a); out = Append(out, a);
...@@ -69,8 +76,15 @@ std::string StrCat(const AlphaNum& a, const AlphaNum& b) { ...@@ -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 StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c) {
std::string result; 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( strings_internal::STLStringResizeUninitialized(
&result, a.size() + b.size() + c.size()); &result, static_cast<size_t>(result_size));
char* const begin = &result[0]; char* const begin = &result[0];
char* out = begin; char* out = begin;
out = Append(out, a); out = Append(out, a);
...@@ -83,8 +97,16 @@ std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c) { ...@@ -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, std::string StrCat(const AlphaNum& a, const AlphaNum& b, const AlphaNum& c,
const AlphaNum& d) { const AlphaNum& d) {
std::string result; 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( 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* const begin = &result[0];
char* out = begin; char* out = begin;
out = Append(out, a); out = Append(out, a);
...@@ -224,9 +246,16 @@ void SingleArgStrAppend(std::string& str, unsigned long long x) { ...@@ -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 CatPieces(std::initializer_list<absl::string_view> pieces) {
std::string result; std::string result;
size_t total_size = 0; // Use uint64_t to prevent size_t overflow. We assume it is not possible for
for (absl::string_view piece : pieces) total_size += piece.size(); // in memory strings to overflow a uint64_t.
strings_internal::STLStringResizeUninitialized(&result, total_size); 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* const begin = &result[0];
char* out = begin; char* out = begin;
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <cassert> #include <cassert>
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <limits>
#include <string> #include <string>
#include "absl/base/config.h" #include "absl/base/config.h"
...@@ -84,6 +85,9 @@ void SubstituteAndAppendArray( ...@@ -84,6 +85,9 @@ void SubstituteAndAppendArray(
// Build the string. // Build the string.
size_t original_size = output->size(); 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, strings_internal::STLStringResizeUninitializedAmortized(output,
original_size + size); original_size + size);
char* target = &(*output)[original_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