From 45c6b771c0bbf3f24872161bde4e6f57ab4d6c29 Mon Sep 17 00:00:00 2001 From: Daniel Brondani Date: Fri, 1 Sep 2023 16:13:26 +0200 Subject: [PATCH] Validate mapping key uniqueness --- include/yaml-cpp/exceptions.h | 11 +++++++++++ include/yaml-cpp/node/detail/impl.h | 2 +- include/yaml-cpp/node/detail/node_data.h | 2 +- src/exceptions.cpp | 1 + src/node_data.cpp | 7 ++++++- test/integration/load_node_test.cpp | 4 ++++ 6 files changed, 24 insertions(+), 3 deletions(-) diff --git a/include/yaml-cpp/exceptions.h b/include/yaml-cpp/exceptions.h index f6b2602ae..a4c55372c 100644 --- a/include/yaml-cpp/exceptions.h +++ b/include/yaml-cpp/exceptions.h @@ -87,6 +87,7 @@ const char* const INVALID_ANCHOR = "invalid anchor"; const char* const INVALID_ALIAS = "invalid alias"; const char* const INVALID_TAG = "invalid tag"; const char* const BAD_FILE = "bad file"; +const char* const NON_UNIQUE_MAP_KEY = "map keys must be unique"; template inline const std::string KEY_NOT_FOUND_WITH_KEY( @@ -298,6 +299,16 @@ class YAML_CPP_API BadFile : public Exception { BadFile(const BadFile&) = default; ~BadFile() YAML_CPP_NOEXCEPT override; }; + +class YAML_CPP_API NonUniqueMapKey : public RepresentationException { + public: + template + NonUniqueMapKey(const Mark& mark_, const Key& key) + : RepresentationException(mark_, ErrorMsg::NON_UNIQUE_MAP_KEY) {} + NonUniqueMapKey(const NonUniqueMapKey&) = default; + ~NonUniqueMapKey() YAML_CPP_NOEXCEPT override; +}; + } // namespace YAML #endif // EXCEPTIONS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/yaml-cpp/node/detail/impl.h b/include/yaml-cpp/node/detail/impl.h index b38038dfd..9138fe6b0 100644 --- a/include/yaml-cpp/node/detail/impl.h +++ b/include/yaml-cpp/node/detail/impl.h @@ -218,7 +218,7 @@ inline void node_data::force_insert(const Key& key, const Value& value, node& k = convert_to_node(key, pMemory); node& v = convert_to_node(value, pMemory); - insert_map_pair(k, v); + insert_map_pair(k, v, true); } template diff --git a/include/yaml-cpp/node/detail/node_data.h b/include/yaml-cpp/node/detail/node_data.h index 07cf81aa0..ed7d9cdbf 100644 --- a/include/yaml-cpp/node/detail/node_data.h +++ b/include/yaml-cpp/node/detail/node_data.h @@ -90,7 +90,7 @@ class YAML_CPP_API node_data { void reset_sequence(); void reset_map(); - void insert_map_pair(node& key, node& value); + void insert_map_pair(node& key, node& value, bool force = false); void convert_to_map(const shared_memory_holder& pMemory); void convert_sequence_to_map(const shared_memory_holder& pMemory); diff --git a/src/exceptions.cpp b/src/exceptions.cpp index 43a7976e9..af99fd6b7 100644 --- a/src/exceptions.cpp +++ b/src/exceptions.cpp @@ -17,4 +17,5 @@ BadPushback::~BadPushback() YAML_CPP_NOEXCEPT = default; BadInsert::~BadInsert() YAML_CPP_NOEXCEPT = default; EmitterException::~EmitterException() YAML_CPP_NOEXCEPT = default; BadFile::~BadFile() YAML_CPP_NOEXCEPT = default; +NonUniqueMapKey::~NonUniqueMapKey() YAML_CPP_NOEXCEPT = default; } // namespace YAML diff --git a/src/node_data.cpp b/src/node_data.cpp index 8f5422ae6..23ad892e4 100644 --- a/src/node_data.cpp +++ b/src/node_data.cpp @@ -279,7 +279,12 @@ void node_data::reset_map() { m_undefinedPairs.clear(); } -void node_data::insert_map_pair(node& key, node& value) { +void node_data::insert_map_pair(node& key, node& value, bool force) { + if (!force && !key.scalar().empty()) + for (const auto& mapEntry : m_map) + if (mapEntry.first->scalar() == key.scalar()) + throw NonUniqueMapKey(m_mark, key); + m_map.emplace_back(&key, &value); if (!key.is_defined() || !value.is_defined()) diff --git a/test/integration/load_node_test.cpp b/test/integration/load_node_test.cpp index 9d0c790fd..37355aa21 100644 --- a/test/integration/load_node_test.cpp +++ b/test/integration/load_node_test.cpp @@ -360,5 +360,9 @@ TEST(LoadNodeTest, BlockCRNLEncoded) { EXPECT_EQ(1, node["followup"].as()); } +TEST(LoadNodeTest, NonUniqueMapKey) { + EXPECT_THROW(Load("{a: A, b: B, a: A}"), NonUniqueMapKey); +} + } // namespace } // namespace YAML