From: Pavel Labath Date: Thu, 11 Apr 2019 14:57:34 +0000 (+0000) Subject: YAMLIO: Fix serialization of strings with embedded nuls X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a5a6353ba4f2982ec099639482c5ba0776d825dd;p=llvm YAMLIO: Fix serialization of strings with embedded nuls Summary: A bug/typo in Output::scalarString caused us to round-trip a StringRef through a const char *. This meant that any strings with embedded nuls were unintentionally cut short at the first such character. (It also could have caused accidental buffer overruns, but it seems that all StringRefs coming into this functions were formed from null-terminated strings.) This patch fixes the bug and adds an appropriate test. Reviewers: sammccall, jhenderson Subscribers: kristina, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D60505 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@358176 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Support/YAMLTraits.cpp b/lib/Support/YAMLTraits.cpp index 4b5bf6ad30d..e7932fe4239 100644 --- a/lib/Support/YAMLTraits.cpp +++ b/lib/Support/YAMLTraits.cpp @@ -660,11 +660,6 @@ void Output::scalarString(StringRef &S, QuotingType MustQuote) { return; } - unsigned i = 0; - unsigned j = 0; - unsigned End = S.size(); - const char *Base = S.data(); - const char *const Quote = MustQuote == QuotingType::Single ? "'" : "\""; output(Quote); // Starting quote. @@ -672,11 +667,16 @@ void Output::scalarString(StringRef &S, QuotingType MustQuote) { // present, and will be escaped using a variety of unicode-scalar and special short-form // escapes. This is handled in yaml::escape. if (MustQuote == QuotingType::Double) { - output(yaml::escape(Base, /* EscapePrintable= */ false)); + output(yaml::escape(S, /* EscapePrintable= */ false)); outputUpToEndOfLine(Quote); return; } + unsigned i = 0; + unsigned j = 0; + unsigned End = S.size(); + const char *Base = S.data(); + // When using single-quoted strings, any single quote ' must be doubled to be escaped. while (j < End) { if (S[j] == '\'') { // Escape quotes. diff --git a/unittests/Support/YAMLIOTest.cpp b/unittests/Support/YAMLIOTest.cpp index 26858015bcb..ef14352628a 100644 --- a/unittests/Support/YAMLIOTest.cpp +++ b/unittests/Support/YAMLIOTest.cpp @@ -688,6 +688,7 @@ struct StringTypes { std::string stdstr10; std::string stdstr11; std::string stdstr12; + std::string stdstr13; }; namespace llvm { @@ -718,6 +719,7 @@ namespace yaml { io.mapRequired("stdstr10", st.stdstr10); io.mapRequired("stdstr11", st.stdstr11); io.mapRequired("stdstr12", st.stdstr12); + io.mapRequired("stdstr13", st.stdstr13); } }; } @@ -750,6 +752,7 @@ TEST(YAMLIO, TestReadWriteStringTypes) { map.stdstr10 = "0.2e20"; map.stdstr11 = "0x30"; map.stdstr12 = "- match"; + map.stdstr13.assign("\0a\0b\0", 5); llvm::raw_string_ostream ostr(intermediate); Output yout(ostr); @@ -775,6 +778,7 @@ TEST(YAMLIO, TestReadWriteStringTypes) { EXPECT_NE(std::string::npos, flowOut.find("'@hhh'")); EXPECT_NE(std::string::npos, flowOut.find("''\n")); EXPECT_NE(std::string::npos, flowOut.find("'0000000004000000'\n")); + EXPECT_NE(std::string::npos, flowOut.find("\"\\0a\\0b\\0\"")); { Input yin(intermediate); @@ -794,6 +798,7 @@ TEST(YAMLIO, TestReadWriteStringTypes) { EXPECT_TRUE(map.stdstr4 == "@hhh"); EXPECT_TRUE(map.stdstr5 == ""); EXPECT_TRUE(map.stdstr6 == "0000000004000000"); + EXPECT_EQ(std::string("\0a\0b\0", 5), map.stdstr13); } }