[PATCH] Detect malformed yaml sequence in yaml::Input::beginSequence()

Justin Bogner mail at justinbogner.com
Sat Jan 17 13:15:53 PST 2015


William Fisher <william.w.fisher at gmail.com> writes:
> When reading a yaml::SequenceTraits object, YAMLIO does report an
> error if the yaml item is not a sequence. Instead, YAMLIO reads an
> empty sequence. For example:
>
> ---
> seq:
>     foo: 1
>     bar: 2
> ...
>
> If `seq` is a SequenceTraits object, then reading the above yaml will
> yield `seq` as an empty sequence.  The enclosed patch reports an error
> for the above mapping ("not a sequence")

LGTM with a couple of nits.

> Null and empty nodes are still interpreted as empty sequences:
>
> ---
> seq1:               # Empty node okay
> ---
> seq2:  null       # null okay
> ...
>
> Index: lib/Support/YAMLTraits.cpp
> ===================================================================
> --- lib/Support/YAMLTraits.cpp	(revision 224940)
> +++ lib/Support/YAMLTraits.cpp	(working copy)
> @@ -170,7 +170,16 @@
>  unsigned Input::beginSequence() {
>    if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode)) {
>      return SQ->Entries.size();
> +  } else if (dyn_cast<EmptyHNode>(CurrentNode)) {

This should be isa<EmptyHNode>(CurrentNode), since we don't use the
result.

> +    return 0;
>    }
> +  // Treat case where there's a scalar "null" value as an empty sequence.
> +  if (ScalarHNode *SN = dyn_cast<ScalarHNode>(CurrentNode)) {

Seems odd to use "else if" above and just "if" here. Better to be
consistent.

> +    if (isNull(SN->value()))
> +      return 0;
> +  }
> +  // Any other type of HNode is an error.
> +  setError(CurrentNode, "not a sequence");
>    return 0;
>  }
>  
> @@ -193,10 +202,7 @@
>  }
>  
>  unsigned Input::beginFlowSequence() {
> -  if (SequenceHNode *SQ = dyn_cast<SequenceHNode>(CurrentNode)) {
> -    return SQ->Entries.size();
> -  }
> -  return 0;
> +  return beginSequence();
>  }
>  
>  bool Input::preflightFlowElement(unsigned index, void *&SaveInfo) {
> Index: unittests/Support/YAMLIOTest.cpp
> ===================================================================
> --- unittests/Support/YAMLIOTest.cpp	(revision 224940)
> +++ unittests/Support/YAMLIOTest.cpp	(working copy)
> @@ -46,6 +46,9 @@
>  
>  LLVM_YAML_IS_SEQUENCE_VECTOR(FooBar)
>  
> +struct FooBarContainer {
> +  FooBarSequence fbs;
> +};
>  
>  namespace llvm {
>  namespace yaml {
> @@ -56,6 +59,13 @@
>        io.mapRequired("bar",    fb.bar);
>      }
>    };
> +
> +  template <>
> +  struct MappingTraits<FooBarContainer> {
> +    static void mapping(IO &io, FooBarContainer& fb) {
> +      io.mapRequired("fbs",    fb.fbs);
> +    }
> +  };
>  }
>  }
>  
> @@ -109,8 +119,85 @@
>    EXPECT_EQ(map2.bar, 9);
>  }
>  
> +//
> +// Test the reading of a map containing a yaml sequence of mappings
> +//
> +TEST(YAMLIO, TestContainerSequenceMapRead) {
> +  {
> +    FooBarContainer cont;
> +    Input yin2("---\nfbs:\n - foo: 3\n   bar: 5\n - foo: 7\n   bar: 9\n...\n");
> +    yin2 >> cont;
> +  
> +    EXPECT_FALSE(yin2.error());
> +    EXPECT_EQ(cont.fbs.size(), 2UL);
> +    EXPECT_EQ(cont.fbs[0].foo, 3);
> +    EXPECT_EQ(cont.fbs[0].bar, 5);
> +    EXPECT_EQ(cont.fbs[1].foo, 7);
> +    EXPECT_EQ(cont.fbs[1].bar, 9);
> +  }
>  
> +  {
> +    FooBarContainer cont;
> +    Input yin("---\nfbs:\n...\n");
> +    yin >> cont;
> +    // Okay: Empty node represents an empty array.
> +    EXPECT_FALSE(yin.error());
> +    EXPECT_EQ(cont.fbs.size(), 0UL);
> +  }
> +
> +  {
> +    FooBarContainer cont;
> +    Input yin("---\nfbs: !!null null\n...\n");
> +    yin >> cont;
> +    // Okay: null represents an empty array.
> +    EXPECT_FALSE(yin.error());
> +    EXPECT_EQ(cont.fbs.size(), 0UL);
> +  }
> +
> +  {
> +    FooBarContainer cont;
> +    Input yin("---\nfbs: ~\n...\n");
> +    yin >> cont;
> +    // Okay: null represents an empty array.
> +    EXPECT_FALSE(yin.error());
> +    EXPECT_EQ(cont.fbs.size(), 0UL);
> +  }
> +
> +  {
> +    FooBarContainer cont;
> +    Input yin("---\nfbs: null\n...\n");
> +    yin >> cont;
> +    // Okay: null represents an empty array.
> +    EXPECT_FALSE(yin.error());
> +    EXPECT_EQ(cont.fbs.size(), 0UL);
> +  }
> +}
> +
>  //
> +// Test the reading of a map containing a malformed yaml sequence
> +// 
> +TEST(YAMLIO, TestMalformedContainerSequenceMapRead) {
> +  {
> +    FooBarContainer cont;
> +    Input yin("---\nfbs:\n   foo: 3\n   bar: 5\n...\n", nullptr, 
> +              suppressErrorMessages);
> +    yin >> cont;
> +    // Error: fbs is not a sequence.
> +    EXPECT_TRUE(!!yin.error());
> +    EXPECT_EQ(cont.fbs.size(), 0UL);
> +  }
> +
> +  {
> +    FooBarContainer cont;
> +    Input yin("---\nfbs: 'scalar'\n...\n", nullptr, suppressErrorMessages);
> +    yin >> cont;
> +    // This should be an error.
> +    EXPECT_TRUE(!!yin.error());
> +    EXPECT_EQ(cont.fbs.size(), 0UL);
> +  }
> +}
> +
> +//
>  // Test writing then reading back a sequence of mappings
>  //
>  TEST(YAMLIO, TestSequenceMapWriteAndRead) {
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits



More information about the llvm-commits mailing list