Check that total compound dictionary size does not overflow.

Thanks to @0xazanul who reported the problem in #1438

PiperOrigin-RevId: 896638456
diff --git a/c/common/platform.h b/c/common/platform.h
index e1254d5..8080cbb 100644
--- a/c/common/platform.h
+++ b/c/common/platform.h
@@ -24,6 +24,7 @@
 #ifndef BROTLI_COMMON_PLATFORM_H_
 #define BROTLI_COMMON_PLATFORM_H_
 
+#include <limits.h>
 #include <string.h>  /* IWYU pragma: export memcmp, memcpy, memset */
 #include <stdlib.h>  /* IWYU pragma: export exit, free, malloc */
 #include <sys/types.h>  /* should include endian.h for us */
@@ -522,6 +523,14 @@
 #define BROTLI_MIN(T, A, B) (brotli_min_ ## T((A), (B)))
 #define BROTLI_MAX(T, A, B) (brotli_max_ ## T((A), (B)))
 
+static BROTLI_INLINE int brotli_safe_add_int(int a, int b, int* result) {
+  if (b > 0 && a > INT_MAX - b) return 0;
+  if (b < 0 && a < INT_MIN - b) return 0;
+  *result = a + b;
+  return 1;
+}
+#define BROTLI_SAFE_ADD(T, A, B, R) (brotli_safe_add_ ## T((A), (B), (R)))
+
 #define BROTLI_SWAP(T, A, I, J) { \
   T __brotli_swap_tmp = (A)[(I)]; \
   (A)[(I)] = (A)[(J)];            \
@@ -607,6 +616,7 @@
   BROTLI_UNUSED(&brotli_max_uint32_t);
   BROTLI_UNUSED(&brotli_min_uint8_t);
   BROTLI_UNUSED(&brotli_max_uint8_t);
+  BROTLI_UNUSED(&brotli_safe_add_int);
   BROTLI_UNUSED(&BrotliDefaultAllocFunc);
   BROTLI_UNUSED(&BrotliDefaultFreeFunc);
   BROTLI_UNUSED(&BrotliRotateRight16);
@@ -615,6 +625,7 @@
 #if BROTLI_ENABLE_DUMP
   BROTLI_UNUSED(&BrotliDump);
 #endif
+}
 
 #if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) && \
     !defined(_M_ARM64EC)
@@ -654,7 +665,6 @@
 #elif defined(BROTLI_TZCNT64)
 #define BROTLI_MAX_SIMD_QUALITY 6
 #endif
-}
 
 #if defined(_MSC_VER)
 #define BROTLI_CRASH() __debugbreak(), (void)abort()
diff --git a/c/dec/decode.c b/c/dec/decode.c
index 19c7e02..c4972a5 100644
--- a/c/dec/decode.c
+++ b/c/dec/decode.c
@@ -1526,6 +1526,8 @@
 static BROTLI_BOOL AttachCompoundDictionary(
     BrotliDecoderState* state, const uint8_t* data, size_t size) {
   BrotliDecoderCompoundDictionary* addon = state->compound_dictionary;
+  int new_size = (int)size;
+  if (new_size < 0 || (size_t)new_size != size) return BROTLI_FALSE;
   if (state->state != BROTLI_STATE_UNINITED) return BROTLI_FALSE;
   if (!addon) {
     addon = (BrotliDecoderCompoundDictionary*)BROTLI_DECODER_ALLOC(
@@ -1540,10 +1542,13 @@
     state->compound_dictionary = addon;
   }
   if (addon->num_chunks == 15) return BROTLI_FALSE;
+  if (!BROTLI_SAFE_ADD(int, addon->total_size, new_size, &new_size)) {
+    return BROTLI_FALSE;
+  }
   addon->chunks[addon->num_chunks] = data;
   addon->num_chunks++;
-  addon->total_size += (int)size;
-  addon->chunk_offsets[addon->num_chunks] = addon->total_size;
+  addon->total_size = new_size;
+  addon->chunk_offsets[addon->num_chunks] = new_size;
   return BROTLI_TRUE;
 }