Fix size_t narrowing and pointer arithmetic overflow in absl::chunked_queue::resize

In `absl::chunked_queue::resize(size_t)`, the difference between `new_size` and `size()` was being stored in a `ptrdiff_t`. When resizing to large values (such as `SIZE_MAX`), this narrowing conversion could overflow, resulting in a negative delta and causing an out-of-bounds heap write during element construction.

This change fixes the issue by:
- Keeping `to_add` as `size_t`.
- Clamping `to_add` to the remaining element capacity of the current tail block before adding it to `start`, preventing pointer arithmetic overflow or wrap-around.
- Updating `iterator_common::IncrBy(size_t)` to compare element counts rather than computing `ptr + n` against `limit`, avoiding potential pointer wrap-around.
- Adding a unit test (`ResizeOverflowSafe`) using a custom limited allocator to verify safe handling of large resize requests.

PiperOrigin-RevId: 945278731
Change-Id: Id400b3813f95d59ea738c58c8c1af3e6e8a836e4
diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel
index 22a0a23..9afef5d 100644
--- a/absl/container/BUILD.bazel
+++ b/absl/container/BUILD.bazel
@@ -1426,6 +1426,7 @@
         ":test_allocator",
         "//absl/base:core_headers",
         "//absl/base:hardening",
+        "//absl/base:throw_delegate",
         "//absl/strings",
         "@googletest//:gtest",
         "@googletest//:gtest_main",
diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt
index 005548f..5ffef3f 100644
--- a/absl/container/CMakeLists.txt
+++ b/absl/container/CMakeLists.txt
@@ -1239,5 +1239,6 @@
     absl::hardening
     absl::strings
     absl::test_allocator
+    absl::throw_delegate
     GTest::gmock_main
 )
diff --git a/absl/container/chunked_queue.h b/absl/container/chunked_queue.h
index 2ec7184..0e686ca 100644
--- a/absl/container/chunked_queue.h
+++ b/absl/container/chunked_queue.h
@@ -154,8 +154,8 @@
     }
 
     void IncrBy(size_t n) {
-      while (ptr + n > limit) {
-        n -= limit - ptr;
+      while (n > static_cast<size_t>(limit - ptr)) {
+        n -= static_cast<size_t>(limit - ptr);
         *this = iterator_common(block->next());
       }
       ptr += n;
@@ -634,15 +634,16 @@
 template <typename T, size_t BLo, size_t BHi, typename Allocator>
 void chunked_queue<T, BLo, BHi, Allocator>::resize(size_t new_size) {
   while (new_size > size()) {
-    ptrdiff_t to_add = new_size - size();
     if (tail_.ptr == tail_.limit) {
       AddTailBlock();
     }
+    size_t to_add = (std::min)(new_size - size(),
+                               static_cast<size_t>(tail_.limit - tail_.ptr));
     T* start = tail_.ptr;
-    T* limit = (std::min)(tail_.limit, start + to_add);
+    T* limit = start + to_add;
     Construct(start, limit);
     tail_.ptr = limit;
-    alloc_and_size_.size += limit - start;
+    alloc_and_size_.size += to_add;
   }
   if (size() == new_size) {
     return;
diff --git a/absl/container/chunked_queue_test.cc b/absl/container/chunked_queue_test.cc
index cc50f6b..9540ff9 100644
--- a/absl/container/chunked_queue_test.cc
+++ b/absl/container/chunked_queue_test.cc
@@ -20,8 +20,10 @@
 #include <deque>
 #include <forward_list>
 #include <iterator>
+#include <limits>
 #include <list>
 #include <memory>
+#include <new>
 #include <string>
 #include <type_traits>
 #include <utility>
@@ -31,6 +33,7 @@
 #include "gtest/gtest.h"
 #include "absl/base/internal/hardening.h"
 #include "absl/base/macros.h"
+#include "absl/base/throw_delegate.h"
 #include "absl/container/internal/test_allocator.h"
 #include "absl/strings/str_cat.h"
 
@@ -435,6 +438,51 @@
   EXPECT_EQ(2, q.size());
 }
 
+template <class T>
+struct LimitedAllocator {
+  using value_type = T;
+  int* alloc_count;
+  int max_allocs;
+
+  explicit LimitedAllocator(int* count, int max)
+      : alloc_count(count), max_allocs(max) {}
+  template <class U>
+  LimitedAllocator(const LimitedAllocator<U>& other)
+      : alloc_count(other.alloc_count), max_allocs(other.max_allocs) {}
+
+  T* allocate(size_t n) {
+    if (*alloc_count >= max_allocs) {
+      absl::ThrowStdBadAlloc();
+    }
+    ++*alloc_count;
+    return std::allocator<T>().allocate(n);
+  }
+
+  void deallocate(T* p, size_t n) {
+    std::allocator<T>().deallocate(p, n);
+  }
+
+  template <class U>
+  bool operator==(const LimitedAllocator<U>& other) const {
+    return alloc_count == other.alloc_count;
+  }
+  template <class U>
+  bool operator!=(const LimitedAllocator<U>& other) const {
+    return !(*this == other);
+  }
+};
+
+TEST(ChunkedQueue, ResizeOverflowSafe) {
+  int alloc_count = 0;
+  absl::chunked_queue<int64_t, 0, 0, LimitedAllocator<int64_t>> q(
+      LimitedAllocator<int64_t>(&alloc_count, 5));
+#ifdef ABSL_HAVE_EXCEPTIONS
+  EXPECT_THROW(q.resize(std::numeric_limits<size_t>::max()), std::bad_alloc);
+#else
+  EXPECT_DEATH_IF_SUPPORTED(q.resize(std::numeric_limits<size_t>::max()), "");
+#endif
+}
+
 TEST(ChunkedQueue, MaxSize) {
   absl::chunked_queue<int64_t> q;
   EXPECT_GE(q.max_size(),