mirror of
https://github.com/jbeder/yaml-cpp.git
synced 2025-09-09 04:41:16 +00:00
fix(src,include,test): fixed multiple cases where a bad yaml was accepted.
Signed-off-by: Federico Di Pierro <nierro92@gmail.com>
This commit is contained in:

committed by
Jesse Beder

parent
47cd2725d6
commit
1f2b841949
@@ -48,6 +48,8 @@ const char* const UNKNOWN_TOKEN = "unknown token";
|
|||||||
const char* const DOC_IN_SCALAR = "illegal document indicator in scalar";
|
const char* const DOC_IN_SCALAR = "illegal document indicator in scalar";
|
||||||
const char* const EOF_IN_SCALAR = "illegal EOF in scalar";
|
const char* const EOF_IN_SCALAR = "illegal EOF in scalar";
|
||||||
const char* const CHAR_IN_SCALAR = "illegal character in scalar";
|
const char* const CHAR_IN_SCALAR = "illegal character in scalar";
|
||||||
|
const char* const UNEXPECTED_SCALAR = "unexpected scalar";
|
||||||
|
const char* const UNEXPECTED_FLOW = "plain value cannot start with flow indicator character";
|
||||||
const char* const TAB_IN_INDENTATION =
|
const char* const TAB_IN_INDENTATION =
|
||||||
"illegal tab when looking for indentation";
|
"illegal tab when looking for indentation";
|
||||||
const char* const FLOW_END = "illegal flow end";
|
const char* const FLOW_END = "illegal flow end";
|
||||||
|
@@ -13,6 +13,7 @@ Scanner::Scanner(std::istream& in)
|
|||||||
m_startedStream(false),
|
m_startedStream(false),
|
||||||
m_endedStream(false),
|
m_endedStream(false),
|
||||||
m_simpleKeyAllowed(false),
|
m_simpleKeyAllowed(false),
|
||||||
|
m_scalarValueAllowed(false),
|
||||||
m_canBeJSONFlow(false),
|
m_canBeJSONFlow(false),
|
||||||
m_simpleKeys{},
|
m_simpleKeys{},
|
||||||
m_indents{},
|
m_indents{},
|
||||||
@@ -127,6 +128,17 @@ void Scanner::ScanNextToken() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (INPUT.peek() == Keys::FlowEntry) {
|
if (INPUT.peek() == Keys::FlowEntry) {
|
||||||
|
// values starting with `,` are not allowed.
|
||||||
|
// eg: reject `,foo`
|
||||||
|
if (INPUT.column() == 0) {
|
||||||
|
throw ParserException(INPUT.mark(), ErrorMsg::UNEXPECTED_FLOW);
|
||||||
|
}
|
||||||
|
// if we already parsed a quoted scalar value and we are not in a flow,
|
||||||
|
// then `,` is not a valid character.
|
||||||
|
// eg: reject `"foo",`
|
||||||
|
if (!m_scalarValueAllowed) {
|
||||||
|
throw ParserException(INPUT.mark(), ErrorMsg::UNEXPECTED_SCALAR);
|
||||||
|
}
|
||||||
return ScanFlowEntry();
|
return ScanFlowEntry();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,6 +171,13 @@ void Scanner::ScanNextToken() {
|
|||||||
return ScanBlockScalar();
|
return ScanBlockScalar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we already parsed a quoted scalar value in this line,
|
||||||
|
// another scalar value is an error.
|
||||||
|
// eg: reject `"foo" "bar"`
|
||||||
|
if (!m_scalarValueAllowed) {
|
||||||
|
throw ParserException(INPUT.mark(), ErrorMsg::UNEXPECTED_SCALAR);
|
||||||
|
}
|
||||||
|
|
||||||
if (INPUT.peek() == '\'' || INPUT.peek() == '\"') {
|
if (INPUT.peek() == '\'' || INPUT.peek() == '\"') {
|
||||||
return ScanQuotedScalar();
|
return ScanQuotedScalar();
|
||||||
}
|
}
|
||||||
@@ -203,6 +222,9 @@ void Scanner::ScanToNextToken() {
|
|||||||
// oh yeah, and let's get rid of that simple key
|
// oh yeah, and let's get rid of that simple key
|
||||||
InvalidateSimpleKey();
|
InvalidateSimpleKey();
|
||||||
|
|
||||||
|
// new line - we accept a scalar value now
|
||||||
|
m_scalarValueAllowed = true;
|
||||||
|
|
||||||
// new line - we may be able to accept a simple key now
|
// new line - we may be able to accept a simple key now
|
||||||
if (InBlockContext()) {
|
if (InBlockContext()) {
|
||||||
m_simpleKeyAllowed = true;
|
m_simpleKeyAllowed = true;
|
||||||
@@ -245,6 +267,7 @@ const RegEx& Scanner::GetValueRegex() const {
|
|||||||
void Scanner::StartStream() {
|
void Scanner::StartStream() {
|
||||||
m_startedStream = true;
|
m_startedStream = true;
|
||||||
m_simpleKeyAllowed = true;
|
m_simpleKeyAllowed = true;
|
||||||
|
m_scalarValueAllowed = true;
|
||||||
std::unique_ptr<IndentMarker> pIndent(
|
std::unique_ptr<IndentMarker> pIndent(
|
||||||
new IndentMarker(-1, IndentMarker::NONE));
|
new IndentMarker(-1, IndentMarker::NONE));
|
||||||
m_indentRefs.push_back(std::move(pIndent));
|
m_indentRefs.push_back(std::move(pIndent));
|
||||||
@@ -261,6 +284,7 @@ void Scanner::EndStream() {
|
|||||||
PopAllSimpleKeys();
|
PopAllSimpleKeys();
|
||||||
|
|
||||||
m_simpleKeyAllowed = false;
|
m_simpleKeyAllowed = false;
|
||||||
|
m_scalarValueAllowed = false;
|
||||||
m_endedStream = true;
|
m_endedStream = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -177,6 +177,7 @@ class Scanner {
|
|||||||
// state info
|
// state info
|
||||||
bool m_startedStream, m_endedStream;
|
bool m_startedStream, m_endedStream;
|
||||||
bool m_simpleKeyAllowed;
|
bool m_simpleKeyAllowed;
|
||||||
|
bool m_scalarValueAllowed;
|
||||||
bool m_canBeJSONFlow;
|
bool m_canBeJSONFlow;
|
||||||
std::stack<SimpleKey> m_simpleKeys;
|
std::stack<SimpleKey> m_simpleKeys;
|
||||||
std::stack<IndentMarker *> m_indents;
|
std::stack<IndentMarker *> m_indents;
|
||||||
|
@@ -211,6 +211,9 @@ void Scanner::ScanValue() {
|
|||||||
m_simpleKeyAllowed = InBlockContext();
|
m_simpleKeyAllowed = InBlockContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we are parsing a `key: value` pair; scalars are always allowed
|
||||||
|
m_scalarValueAllowed = true;
|
||||||
|
|
||||||
// eat
|
// eat
|
||||||
Mark mark = INPUT.mark();
|
Mark mark = INPUT.mark();
|
||||||
INPUT.eat(1);
|
INPUT.eat(1);
|
||||||
@@ -360,6 +363,10 @@ void Scanner::ScanQuotedScalar() {
|
|||||||
// and scan
|
// and scan
|
||||||
scalar = ScanScalar(INPUT, params);
|
scalar = ScanScalar(INPUT, params);
|
||||||
m_simpleKeyAllowed = false;
|
m_simpleKeyAllowed = false;
|
||||||
|
// we just scanned a quoted scalar;
|
||||||
|
// we can only have another scalar in this line
|
||||||
|
// if we are in a flow, eg: `[ "foo", "bar" ]` is ok, but `"foo", "bar"` isn't.
|
||||||
|
m_scalarValueAllowed = InFlowContext();
|
||||||
m_canBeJSONFlow = true;
|
m_canBeJSONFlow = true;
|
||||||
|
|
||||||
Token token(Token::NON_PLAIN_SCALAR, mark);
|
Token token(Token::NON_PLAIN_SCALAR, mark);
|
||||||
|
@@ -334,6 +334,69 @@ TEST(NodeTest, LoadQuotedNull) {
|
|||||||
EXPECT_EQ(node.as<std::string>(), "null");
|
EXPECT_EQ(node.as<std::string>(), "null");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(NodeTest, LoadNonClosedQuotedString) {
|
||||||
|
EXPECT_THROW(Load(R"("foo)"), ParserException);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(NodeTest, LoadWrongQuotedString) {
|
||||||
|
EXPECT_THROW(Load(R"("foo" [)"), ParserException);
|
||||||
|
EXPECT_THROW(Load(R"("foo", [)"), ParserException);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(NodeTest, LoadUnquotedQuotedStrings) {
|
||||||
|
Node node = Load(R"(foo,"bar")");
|
||||||
|
EXPECT_EQ(node.as<std::string>(), "foo,\"bar\"");
|
||||||
|
|
||||||
|
node = Load(R"(foo,bar)");
|
||||||
|
EXPECT_EQ(node.as<std::string>(), "foo,bar");
|
||||||
|
|
||||||
|
node = Load(R"(foo,)");
|
||||||
|
EXPECT_EQ(node.as<std::string>(), "foo,");
|
||||||
|
|
||||||
|
node = Load(R"(foo "bar")");
|
||||||
|
EXPECT_EQ(node.as<std::string>(), "foo \"bar\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(NodeTest, LoadCommaSeparatedStrings) {
|
||||||
|
EXPECT_THROW(Load(R"("foo","bar")"), ParserException);
|
||||||
|
EXPECT_THROW(Load(R"("foo",bar)"), ParserException);
|
||||||
|
EXPECT_THROW(Load(R"(,)"), ParserException);
|
||||||
|
EXPECT_THROW(Load(R"("foo",)"), ParserException);
|
||||||
|
EXPECT_THROW(Load(R"("foo","")"), ParserException);
|
||||||
|
EXPECT_THROW(Load(R"("foo",)"), ParserException);
|
||||||
|
EXPECT_THROW(Load(R"(,"foo")"), ParserException);
|
||||||
|
EXPECT_THROW(Load(R"(,foo)"), ParserException);
|
||||||
|
|
||||||
|
const char *doc_ok = R"(
|
||||||
|
top
|
||||||
|
, aa
|
||||||
|
)";
|
||||||
|
EXPECT_NO_THROW(Load(doc_ok));
|
||||||
|
|
||||||
|
const char *doc_ok_2 = R"(
|
||||||
|
top
|
||||||
|
, "aa"
|
||||||
|
)";
|
||||||
|
EXPECT_NO_THROW(Load(doc_ok_2));
|
||||||
|
|
||||||
|
const char *doc_fail = R"(
|
||||||
|
"top"
|
||||||
|
, "aa"
|
||||||
|
)";
|
||||||
|
EXPECT_THROW(Load(doc_fail), ParserException);
|
||||||
|
|
||||||
|
const char *doc_fail_2 = R"(
|
||||||
|
"top"
|
||||||
|
, aa
|
||||||
|
)";
|
||||||
|
EXPECT_THROW(Load(doc_fail_2), ParserException);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(NodeTest, LoadSameLineStrings) {
|
||||||
|
EXPECT_THROW(Load(R"("foo" "bar")"), ParserException);
|
||||||
|
EXPECT_THROW(Load(R"("foo" bar)"), ParserException);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(NodeTest, LoadTagWithParenthesis) {
|
TEST(NodeTest, LoadTagWithParenthesis) {
|
||||||
Node node = Load("!Complex(Tag) foo");
|
Node node = Load("!Complex(Tag) foo");
|
||||||
EXPECT_EQ(node.Tag(), "!Complex(Tag)");
|
EXPECT_EQ(node.Tag(), "!Complex(Tag)");
|
||||||
|
Reference in New Issue
Block a user