Skip to content

Commit d7e1257

Browse files
committed
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 llvm-svn: 358176
1 parent 34686b6 commit d7e1257

File tree

2 files changed

+11
-6
lines changed

2 files changed

+11
-6
lines changed

llvm/lib/Support/YAMLTraits.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -660,23 +660,23 @@ void Output::scalarString(StringRef &S, QuotingType MustQuote) {
660660
return;
661661
}
662662

663-
unsigned i = 0;
664-
unsigned j = 0;
665-
unsigned End = S.size();
666-
const char *Base = S.data();
667-
668663
const char *const Quote = MustQuote == QuotingType::Single ? "'" : "\"";
669664
output(Quote); // Starting quote.
670665

671666
// When using double-quoted strings (and only in that case), non-printable characters may be
672667
// present, and will be escaped using a variety of unicode-scalar and special short-form
673668
// escapes. This is handled in yaml::escape.
674669
if (MustQuote == QuotingType::Double) {
675-
output(yaml::escape(Base, /* EscapePrintable= */ false));
670+
output(yaml::escape(S, /* EscapePrintable= */ false));
676671
outputUpToEndOfLine(Quote);
677672
return;
678673
}
679674

675+
unsigned i = 0;
676+
unsigned j = 0;
677+
unsigned End = S.size();
678+
const char *Base = S.data();
679+
680680
// When using single-quoted strings, any single quote ' must be doubled to be escaped.
681681
while (j < End) {
682682
if (S[j] == '\'') { // Escape quotes.

llvm/unittests/Support/YAMLIOTest.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,7 @@ struct StringTypes {
688688
std::string stdstr10;
689689
std::string stdstr11;
690690
std::string stdstr12;
691+
std::string stdstr13;
691692
};
692693

693694
namespace llvm {
@@ -718,6 +719,7 @@ namespace yaml {
718719
io.mapRequired("stdstr10", st.stdstr10);
719720
io.mapRequired("stdstr11", st.stdstr11);
720721
io.mapRequired("stdstr12", st.stdstr12);
722+
io.mapRequired("stdstr13", st.stdstr13);
721723
}
722724
};
723725
}
@@ -750,6 +752,7 @@ TEST(YAMLIO, TestReadWriteStringTypes) {
750752
map.stdstr10 = "0.2e20";
751753
map.stdstr11 = "0x30";
752754
map.stdstr12 = "- match";
755+
map.stdstr13.assign("\0a\0b\0", 5);
753756

754757
llvm::raw_string_ostream ostr(intermediate);
755758
Output yout(ostr);
@@ -775,6 +778,7 @@ TEST(YAMLIO, TestReadWriteStringTypes) {
775778
EXPECT_NE(std::string::npos, flowOut.find("'@hhh'"));
776779
EXPECT_NE(std::string::npos, flowOut.find("''\n"));
777780
EXPECT_NE(std::string::npos, flowOut.find("'0000000004000000'\n"));
781+
EXPECT_NE(std::string::npos, flowOut.find("\"\\0a\\0b\\0\""));
778782

779783
{
780784
Input yin(intermediate);
@@ -794,6 +798,7 @@ TEST(YAMLIO, TestReadWriteStringTypes) {
794798
EXPECT_TRUE(map.stdstr4 == "@hhh");
795799
EXPECT_TRUE(map.stdstr5 == "");
796800
EXPECT_TRUE(map.stdstr6 == "0000000004000000");
801+
EXPECT_EQ(std::string("\0a\0b\0", 5), map.stdstr13);
797802
}
798803
}
799804

0 commit comments

Comments
 (0)