Mitigate use-after-free due to overflow of RefcountAndFlags::count_

Detects refcounts for Cord going too high, resulting in a fatal error in that case. Since the check happens after the increment, we stay conservative with the bounds and leave a good deal of margin to mitigate the chances of Unref() racing with Ref() and happening earlier than its check, which could still result in a use-after-free.

PiperOrigin-RevId: 945345773
Change-Id: Ide1151618ae836fd30dbc0a476e29ba85ca45862
diff --git a/absl/strings/internal/cord_internal.cc b/absl/strings/internal/cord_internal.cc
index 57d9d38..becfc6a 100644
--- a/absl/strings/internal/cord_internal.cc
+++ b/absl/strings/internal/cord_internal.cc
@@ -31,6 +31,10 @@
 ABSL_CONST_INIT std::atomic<bool> shallow_subcords_enabled(
     kCordShallowSubcordsDefault);
 
+void RefcountAndFlags::IncrementOverflow() {
+  ABSL_INTERNAL_LOG(FATAL, "refcount is too large and vulnerable to overflow");
+}
+
 void LogFatalNodeType(CordRep* rep) {
   ABSL_INTERNAL_LOG(FATAL, absl::StrCat("Unexpected node type: ",
                                         static_cast<int>(rep->tag)));
diff --git a/absl/strings/internal/cord_internal.h b/absl/strings/internal/cord_internal.h
index 27a8b9f..98dc4b5 100644
--- a/absl/strings/internal/cord_internal.h
+++ b/absl/strings/internal/cord_internal.h
@@ -20,11 +20,13 @@
 #include <cstddef>
 #include <cstdint>
 #include <cstring>
+#include <limits>
 #include <string>
 
 #include "absl/base/attributes.h"
 #include "absl/base/config.h"
 #include "absl/base/internal/endian.h"
+#include "absl/base/internal/raw_logging.h"
 #include "absl/base/macros.h"
 #include "absl/base/nullability.h"
 #include "absl/base/optimization.h"
@@ -133,9 +135,18 @@
   struct Immortal {};
   explicit constexpr RefcountAndFlags(Immortal) : count_(kImmortalFlag) {}
 
+  static void IncrementOverflow();
+
   // Increments the reference count. Imposes no memory ordering.
   inline void Increment() {
-    count_.fetch_add(kRefIncrement, std::memory_order_relaxed);
+    const int32_t prev_count =
+        count_.fetch_add(kRefIncrement, std::memory_order_relaxed);
+    if (ABSL_PREDICT_FALSE(
+            prev_count >=
+            ((std::numeric_limits<decltype(count_)::value_type>::max)() / 3) *
+                2)) {
+      IncrementOverflow();
+    }
   }
 
   // Asserts that the current refcount is greater than 0. If the refcount is