Log unmarked strongly interned string in SweepInterpreterCache()

Bug: 275005060
Test: manual
Change-Id: I180879ed99170cab4ddc21cd7ffc23c97d31f610
diff --git a/runtime/gc/collector/concurrent_copying.h b/runtime/gc/collector/concurrent_copying.h
index c274fed..888c38a 100644
--- a/runtime/gc/collector/concurrent_copying.h
+++ b/runtime/gc/collector/concurrent_copying.h
@@ -161,6 +161,10 @@
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   void AssertNoThreadMarkStackMapping(Thread* thread) REQUIRES(!mark_stack_lock_);
+  // Dump information about reference `ref` and return it as a string.
+  // Use `ref_name` to name the reference in messages. Each message is prefixed with `indent`.
+  std::string DumpReferenceInfo(mirror::Object* ref, const char* ref_name, const char* indent = "")
+      REQUIRES_SHARED(Locks::mutator_lock_);
 
  private:
   void PushOntoMarkStack(Thread* const self, mirror::Object* obj)
@@ -282,10 +286,6 @@
   void ComputeUnevacFromSpaceLiveRatio();
   void LogFromSpaceRefHolder(mirror::Object* obj, MemberOffset offset)
       REQUIRES_SHARED(Locks::mutator_lock_);
-  // Dump information about reference `ref` and return it as a string.
-  // Use `ref_name` to name the reference in messages. Each message is prefixed with `indent`.
-  std::string DumpReferenceInfo(mirror::Object* ref, const char* ref_name, const char* indent = "")
-      REQUIRES_SHARED(Locks::mutator_lock_);
   // Dump information about heap reference `ref`, referenced from object `obj` at offset `offset`,
   // and return it as a string.
   std::string DumpHeapReference(mirror::Object* obj, MemberOffset offset, mirror::Object* ref)
diff --git a/runtime/thread.cc b/runtime/thread.cc
index a341c56..335b365 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -77,6 +77,7 @@
 #include "handle_scope-inl.h"
 #include "indirect_reference_table-inl.h"
 #include "instrumentation.h"
+#include "intern_table.h"
 #include "interpreter/interpreter.h"
 #include "interpreter/shadow_frame-inl.h"
 #include "java_frame_root_info.h"
@@ -4476,8 +4477,28 @@
       mirror::Object* new_object = visitor->IsMarked(object);
       // We know the string is marked because it's a strongly-interned string that
       // is always alive (see b/117621117 for trying to make those strings weak).
-      CHECK_NE(new_object, nullptr) << "old-string:" << object;
-      if (new_object != object) {
+      if (new_object == nullptr) {
+        // (b/275005060) Currently the problem is reported only on CC GC.
+        // Therefore we log it with more information. But since the failure rate
+        // is quite high, sampling it.
+        if (gUseReadBarrier) {
+          static constexpr size_t kSampleRate = 5;
+          if (MilliTime() % kSampleRate == 0) {
+            Runtime* runtime = Runtime::Current();
+            gc::collector::ConcurrentCopying* cc = runtime->GetHeap()->ConcurrentCopyingCollector();
+            CHECK_NE(cc, nullptr);
+            LOG(FATAL) << cc->DumpReferenceInfo(object, "string")
+                       << " string interned: " << std::boolalpha
+                       << runtime->GetInternTable()->LookupStrong(
+                              Thread::Current(), down_cast<mirror::String*>(object))
+                       << std::noboolalpha;
+          }
+        } else {
+          // Other GCs
+          LOG(FATAL) << __FUNCTION__
+                     << ": IsMarked returned null for a strongly interned string: " << object;
+        }
+      } else if (new_object != object) {
         *value = reinterpret_cast<size_t>(new_object);
       }
       return;