jbeder / yaml-cpp

A YAML parser and emitter in C++
MIT License
5.09k stars 1.83k forks source link

Verifying a "Sequence Node" using operator [], with out-of-bounds value, or a string, converts the Node to a Map #1183

Closed fliser2 closed 1 year ago

fliser2 commented 1 year ago

Trying to verify if a node has a child node, using operator [], if the node is a Sequence node (a yaml list), yaml-cpp converts the parent node to be a Map. See the sample code here:

#include <yaml-cpp/yaml.h>

#include <cassert>
#include <iostream>

int main() {
  std::string yaml =
      R"(
---
b: 
  - 1
  - 2
  - 3
)";
  auto yaml_node = YAML::Load(yaml);
  if (yaml_node["b"]) {
    assert(yaml_node["b"].size() == 3);
    assert(yaml_node["b"].IsSequence());
  }
  if (yaml_node["b"][1]) {
    assert(yaml_node["b"].size() == 3);
    assert(yaml_node["b"].IsSequence());
  }
  if (!yaml_node["b"][4]) {
    assert(yaml_node["b"].size() == 3);
    // this assert passes
    assert(yaml_node["b"].IsMap());
    // this assert crashes
    // assert(yaml_node["b"].IsSequence());
  }

  // reload
  yaml_node = YAML::Load(yaml);
  if (yaml_node["b"]) {
    assert(yaml_node["b"].size() == 3);
    assert(yaml_node["b"].IsSequence());
  }
  if (!yaml_node["b"]["b"]) {
    assert(yaml_node["b"].size() == 3);
    // this assert passes
    assert(yaml_node["b"].IsMap());
    // this assert crashes
    // assert(yaml_node["b"].IsSequence());
  }
}

Exepcted Results: yaml_node["b"] should not change while testing for a non existent node

Actual Results: yaml_node["b"] changes to be a Map if an out-of-bounds verification is done through the operator [] yaml_node["b"] changes to be a Map if a map access is done through the operator []

Workarround: Verify if node is a Sequence, check its size and only access this until the size. Only access the node with a string if it is type is a Map

  if (yaml_node["b"].IsMap() && yaml_node["b"]["b"]);
 // or
  if (yaml_node["b"].IsSequence() && 4 < yaml_node["b"].size() && yaml_node["b"][4]);
jbeder commented 1 year ago

The API expects you to check if it's a sequence first.

fliser2 commented 1 year ago

Seems that this is the expected behavior, it is weird that verifying if a node exists, will change the type of the node. From documentation