Fix PrintableString() for 4-byte UTF-8 sequences.

Test: Additional test in utf_test.
Bug: 128865240
Change-Id: I535e028319393abb17ee258086e47593f80f4ed3
diff --git a/libdexfile/dex/utf.cc b/libdexfile/dex/utf.cc
index ed07568..3eb80b1 100644
--- a/libdexfile/dex/utf.cc
+++ b/libdexfile/dex/utf.cc
@@ -283,10 +283,10 @@
   return result;
 }
 
-std::string PrintableString(const char* utf) {
+std::string PrintableString(const char* utf8) {
   std::string result;
   result += '"';
-  const char* p = utf;
+  const char* p = utf8;
   size_t char_count = CountModifiedUtf8Chars(p);
   for (size_t i = 0; i < char_count; ++i) {
     uint32_t ch = GetUtf16FromUtf8(&p);
@@ -311,6 +311,9 @@
       if (trailing != 0) {
         // All high surrogates will need escaping.
         StringAppendF(&result, "\\u%04x", trailing);
+        // Account for the surrogate pair.
+        ++i;
+        DCHECK_LT(i, char_count);
       }
     }
   }
diff --git a/libdexfile/dex/utf_test.cc b/libdexfile/dex/utf_test.cc
index c7a6a34..919259e 100644
--- a/libdexfile/dex/utf_test.cc
+++ b/libdexfile/dex/utf_test.cc
@@ -19,6 +19,8 @@
 #include <map>
 #include <vector>
 
+#include <android-base/stringprintf.h>
+
 #include "gtest/gtest.h"
 #include "utf-inl.h"
 
@@ -385,4 +387,22 @@
   EXPECT_EQ(static_cast<uint8_t>(kNonAsciiCharacter), hash);
 }
 
+TEST_F(UtfTest, PrintableStringUtf8) {
+  // Note: This is UTF-8, not Modified-UTF-8.
+  const uint8_t kTestSequence[] = { 0xf0, 0x90, 0x80, 0x80, 0 };
+  const char* start = reinterpret_cast<const char*>(kTestSequence);
+  const char* ptr = start;
+  uint32_t pair = GetUtf16FromUtf8(&ptr);
+  ASSERT_EQ(*ptr, '\0');
+  uint16_t leading = GetLeadingUtf16Char(pair);
+  uint16_t trailing = GetTrailingUtf16Char(pair);
+  ASSERT_NE(0u, trailing);
+
+  std::string expected = android::base::StringPrintf("\"\\u%04x\\u%04x\"",
+                                                     static_cast<unsigned>(leading),
+                                                     static_cast<unsigned>(trailing));
+  std::string printable = PrintableString(start);
+  EXPECT_EQ(expected, printable);
+}
+
 }  // namespace art