summaryrefslogtreecommitdiff
path: root/absl/strings/escaping.cc
diff options
context:
space:
mode:
Diffstat (limited to 'absl/strings/escaping.cc')
-rw-r--r--absl/strings/escaping.cc26
1 files changed, 22 insertions, 4 deletions
diff --git a/absl/strings/escaping.cc b/absl/strings/escaping.cc
index 1c0eac42..27d3d98c 100644
--- a/absl/strings/escaping.cc
+++ b/absl/strings/escaping.cc
@@ -362,7 +362,7 @@ std::string CEscapeInternal(absl::string_view src, bool use_hex,
}
/* clang-format off */
-constexpr unsigned char c_escaped_len[256] = {
+constexpr unsigned char kCEscapedLen[256] = {
4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 4, 4, 2, 4, 4, // \t, \n, \r
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // ", '
@@ -387,8 +387,23 @@ constexpr unsigned char c_escaped_len[256] = {
// that UTF-8 bytes are not handled specially.
inline size_t CEscapedLength(absl::string_view src) {
size_t escaped_len = 0;
- for (char c : src)
- escaped_len += c_escaped_len[static_cast<unsigned char>(c)];
+ // The maximum value of kCEscapedLen[x] is 4, so we can escape any string of
+ // length size_t_max/4 without checking for overflow.
+ size_t unchecked_limit =
+ std::min<size_t>(src.size(), std::numeric_limits<size_t>::max() / 4);
+ size_t i = 0;
+ while (i < unchecked_limit) {
+ // Common case: No need to check for overflow.
+ escaped_len += kCEscapedLen[static_cast<unsigned char>(src[i++])];
+ }
+ while (i < src.size()) {
+ // Beyond unchecked_limit we need to check for overflow before adding.
+ size_t char_len = kCEscapedLen[static_cast<unsigned char>(src[i++])];
+ ABSL_INTERNAL_CHECK(
+ escaped_len <= std::numeric_limits<size_t>::max() - char_len,
+ "escaped_len overflow");
+ escaped_len += char_len;
+ }
return escaped_len;
}
@@ -400,12 +415,15 @@ void CEscapeAndAppendInternal(absl::string_view src, std::string* dest) {
}
size_t cur_dest_len = dest->size();
+ ABSL_INTERNAL_CHECK(
+ cur_dest_len <= std::numeric_limits<size_t>::max() - escaped_len,
+ "std::string size overflow");
strings_internal::STLStringResizeUninitialized(dest,
cur_dest_len + escaped_len);
char* append_ptr = &(*dest)[cur_dest_len];
for (char c : src) {
- size_t char_len = c_escaped_len[static_cast<unsigned char>(c)];
+ size_t char_len = kCEscapedLen[static_cast<unsigned char>(c)];
if (char_len == 1) {
*append_ptr++ = c;
} else if (char_len == 2) {