diff --git a/llvm/include/llvm/Support/YAMLTraits.h b/llvm/include/llvm/Support/YAMLTraits.h index f38c85af75f7..d1dd34aef68c 100644 --- a/llvm/include/llvm/Support/YAMLTraits.h +++ b/llvm/include/llvm/Support/YAMLTraits.h @@ -1085,6 +1085,7 @@ private: void scalarString(StringRef &, bool) override; void blockScalarString(StringRef &) override; void setError(const Twine &message) override; + bool hasError() const; bool canElideEmptySequence() override; class HNode { diff --git a/llvm/lib/Support/YAMLTraits.cpp b/llvm/lib/Support/YAMLTraits.cpp index 75fac20a8edb..ccd0f45a514e 100644 --- a/llvm/lib/Support/YAMLTraits.cpp +++ b/llvm/lib/Support/YAMLTraits.cpp @@ -112,7 +112,7 @@ bool Input::mapTag(StringRef Tag, bool Default) { } void Input::beginMapping() { - if (EC) + if (hasError()) return; // CurrentNode can be null if the document is empty. MapHNode *MN = dyn_cast_or_null(CurrentNode); @@ -124,7 +124,7 @@ void Input::beginMapping() { bool Input::preflightKey(const char *Key, bool Required, bool, bool &UseDefault, void *&SaveInfo) { UseDefault = false; - if (EC) + if (hasError()) return false; // CurrentNode is null for empty documents, which is an error in case required @@ -159,7 +159,7 @@ void Input::postflightKey(void *saveInfo) { } void Input::endMapping() { - if (EC) + if (hasError()) return; // CurrentNode can be null if the document is empty. MapHNode *MN = dyn_cast_or_null(CurrentNode); @@ -196,7 +196,7 @@ void Input::endSequence() { } bool Input::preflightElement(unsigned Index, void *&SaveInfo) { - if (EC) + if (hasError()) return false; if (SequenceHNode *SQ = dyn_cast(CurrentNode)) { SaveInfo = CurrentNode; @@ -213,7 +213,7 @@ void Input::postflightElement(void *SaveInfo) { unsigned Input::beginFlowSequence() { return beginSequence(); } bool Input::preflightFlowElement(unsigned index, void *&SaveInfo) { - if (EC) + if (hasError()) return false; if (SequenceHNode *SQ = dyn_cast(CurrentNode)) { SaveInfo = CurrentNode; @@ -271,7 +271,7 @@ bool Input::beginBitSetScalar(bool &DoClear) { } bool Input::bitSetMatch(const char *Str, bool) { - if (EC) + if (hasError()) return false; if (SequenceHNode *SQ = dyn_cast(CurrentNode)) { unsigned Index = 0; @@ -293,7 +293,7 @@ bool Input::bitSetMatch(const char *Str, bool) { } void Input::endBitSetScalar() { - if (EC) + if (hasError()) return; if (SequenceHNode *SQ = dyn_cast(CurrentNode)) { assert(BitValuesUsed.size() == SQ->Entries.size()); @@ -321,6 +321,8 @@ void Input::setError(HNode *hnode, const Twine &message) { this->setError(hnode->_node, message); } +bool Input::hasError() const { return EC || Strm->failed(); } + void Input::setError(Node *node, const Twine &message) { Strm->printError(node, message); EC = make_error_code(errc::invalid_argument); @@ -342,7 +344,7 @@ std::unique_ptr Input::createHNodes(Node *N) { auto SQHNode = llvm::make_unique(N); for (Node &SN : *SQ) { auto Entry = this->createHNodes(&SN); - if (EC) + if (hasError()) break; SQHNode->Entries.push_back(std::move(Entry)); } @@ -363,7 +365,7 @@ std::unique_ptr Input::createHNodes(Node *N) { KeyStr = StringStorage.str().copy(StringAllocator); } auto ValueHNode = this->createHNodes(KVN.getValue()); - if (EC) + if (hasError()) break; mapHNode->Mapping[KeyStr] = std::move(ValueHNode); } diff --git a/llvm/unittests/Support/YAMLIOTest.cpp b/llvm/unittests/Support/YAMLIOTest.cpp index bf70e749b4f0..c3e18d332356 100644 --- a/llvm/unittests/Support/YAMLIOTest.cpp +++ b/llvm/unittests/Support/YAMLIOTest.cpp @@ -2368,3 +2368,11 @@ TEST(YAMLIO, TestMapWithContext) { out); out.clear(); } + +TEST(YAMLIO, InvalidInput) { + // polluting 1 value in the sequence + Input yin("---\n- foo: 3\n bar: 5\n1\n- foo: 3\n bar: 5\n...\n"); + std::vector Data; + yin >> Data; + EXPECT_TRUE((bool)yin.error()); +}