Prevent signed integer overflow in _upb_WireReader_SkipGroup.

When `upb_Message_FindUnknown2` is called with a `depth_limit` of `INT_MIN` on a message containing an unknown group field, `_upb_WireReader_SkipGroup` evaluates `--depth_limit < 0`. Decrementing `INT_MIN` before the bounds check triggers signed integer overflow, wrapping around to `INT_MAX` when not compiled with UBSan and bypassing the recursion depth check.

Check `depth_limit <= 0` in `_upb_WireReader_SkipGroup` before decrementing `depth_limit`, and add a regression unit test for `upb_Message_FindUnknown2` with `INT_MIN` on an unknown group field.

PiperOrigin-RevId: 1000384592
diff --git a/upb/message/unknown_fields_test.cc b/upb/message/unknown_fields_test.cc
index 4355928..64a9bb8 100644
--- a/upb/message/unknown_fields_test.cc
+++ b/upb/message/unknown_fields_test.cc
@@ -12,6 +12,7 @@
 
 #include <string.h>
 
+#include <climits>
 #include <cstddef>
 #include <cstdint>
 #include <string>
@@ -397,4 +398,20 @@
   upb_Arena_Free(arena);
 }
 
+TEST(GeneratedCode, FindUnknown2_NegativeDepthLimitOnGroup) {
+  upb_Arena* arena = upb_Arena_New();
+  upb_test_ModelWithExtensions* msg = upb_test_ModelWithExtensions_new(arena);
+
+  // Field 13 StartGroup (0x6b) followed by Field 13 EndGroup (0x6c).
+  const char group_bytes[] = "\x6b\x6c";
+  ASSERT_TRUE(UPB_PRIVATE(_upb_Message_AddUnknown)(
+      UPB_UPCAST(msg), group_bytes, 2, arena, kUpb_AddUnknown_Copy));
+
+  upb_FindUnknownRet2 result =
+      upb_Message_FindUnknown2(UPB_UPCAST(msg), 13, INT_MIN);
+  EXPECT_EQ(kUpb_FindUnknown_ParseError, result.status);
+
+  upb_Arena_Free(arena);
+}
+
 }  // namespace
diff --git a/upb/wire/reader.c b/upb/wire/reader.c
index 85cd386..8cdec41 100644
--- a/upb/wire/reader.c
+++ b/upb/wire/reader.c
@@ -63,9 +63,10 @@
 const char* UPB_PRIVATE(_upb_WireReader_SkipGroup)(
     const char* ptr, uint32_t tag, int depth_limit,
     upb_EpsCopyInputStream* stream) {
-  if (--depth_limit < 0) {
+  if (depth_limit <= 0) {
     return UPB_PRIVATE(upb_EpsCopyInputStream_ReturnError)(stream);
   }
+  depth_limit--;
   uint32_t end_group_tag = (tag & ~7ULL) | kUpb_WireType_EndGroup;
   while (!upb_EpsCopyInputStream_IsDone(stream, &ptr)) {
     uint32_t tag;