Demangle sr St <simple-id> <simple-id>, a dubious encoding found in the wild.

PiperOrigin-RevId: 641418373
Change-Id: I2999228cccfd18a000725b938a692c0c9004867c
diff --git a/absl/debugging/internal/demangle.cc b/absl/debugging/internal/demangle.cc
index d97dfad..f9dff5d 100644
--- a/absl/debugging/internal/demangle.cc
+++ b/absl/debugging/internal/demangle.cc
@@ -2034,6 +2034,13 @@
 //                         <base-unresolved-name>
 //                   ::= [gs] sr <unresolved-qualifier-level>+ E
 //                         <base-unresolved-name>
+//                   ::= sr St <simple-id> <simple-id>  # nonstandard
+//
+// The last case is not part of the official grammar but has been observed in
+// real-world examples that the GNU demangler (but not the LLVM demangler) is
+// able to decode; see demangle_test.cc for one such symbol name.  The shape
+// sr St <simple-id> <simple-id> was inferred by closed-box testing of the GNU
+// demangler.
 static bool ParseUnresolvedName(State *state) {
   ComplexityGuard guard(state);
   if (guard.IsTooComplex()) return false;
@@ -2067,6 +2074,12 @@
   }
   state->parse_state = copy;
 
+  if (ParseTwoCharToken(state, "sr") && ParseTwoCharToken(state, "St") &&
+      ParseSimpleId(state) && ParseSimpleId(state)) {
+    return true;
+  }
+  state->parse_state = copy;
+
   return false;
 }
 
diff --git a/absl/debugging/internal/demangle_test.cc b/absl/debugging/internal/demangle_test.cc
index 1b305f7..68a759c 100644
--- a/absl/debugging/internal/demangle_test.cc
+++ b/absl/debugging/internal/demangle_test.cc
@@ -1845,6 +1845,35 @@
   EXPECT_STREQ("thread-local initialization routine for ns::var", tmp);
 }
 
+TEST(Demangle, DubiousSrStSymbols) {
+  char tmp[80];
+
+  // GNU demangling (not accepted by LLVM):
+  //
+  // S<std::u<char>::v> f<char>()
+  EXPECT_TRUE(Demangle("_Z1fIcE1SIXsrSt1uIT_E1vEEv", tmp, sizeof(tmp)));
+  EXPECT_STREQ("f<>()", tmp);
+
+  // A real case from the wild.
+  //
+  // GNU demangling (not accepted by LLVM) with line breaks and indentation
+  // added for readability:
+  //
+  // __gnu_cxx::__enable_if<std::__is_char<char>::__value, bool>::__type
+  // std::operator==<char>(
+  //     std::__cxx11::basic_string<char, std::char_traits<char>,
+  //                                std::allocator<char> > const&,
+  //     std::__cxx11::basic_string<char, std::char_traits<char>,
+  //                                std::allocator<char> > const&)
+  EXPECT_TRUE(Demangle(
+      "_ZSteqIcEN9__gnu_cxx11__enable_if"
+      "IXsrSt9__is_charIT_E7__valueEbE"
+      "6__typeE"
+      "RKNSt7__cxx1112basic_stringIS3_St11char_traitsIS3_ESaIS3_EEESE_",
+      tmp, sizeof(tmp)));
+  EXPECT_STREQ("std::operator==<>()", tmp);
+}
+
 // Test one Rust symbol to exercise Demangle's delegation path.  Rust demangling
 // itself is more thoroughly tested in demangle_rust_test.cc.
 TEST(Demangle, DelegatesToDemangleRustSymbolEncoding) {