From 254cb747b787cccd25e4d2a9a5982d30be7145ee Mon Sep 17 00:00:00 2001 From: Danil Alexeev Date: Tue, 22 Aug 2023 15:07:53 +0300 Subject: [PATCH] Core: Add recursion level check for `Array` and `Dictionary` hashing --- core/variant/array.cpp | 13 +++++++++++-- core/variant/array.h | 1 + core/variant/dictionary.cpp | 12 ++++++++++-- core/variant/dictionary.h | 1 + core/variant/variant.cpp | 10 +++++++--- core/variant/variant.h | 1 + 6 files changed, 31 insertions(+), 7 deletions(-) diff --git a/core/variant/array.cpp b/core/variant/array.cpp index 539363b37..33196c301 100644 --- a/core/variant/array.cpp +++ b/core/variant/array.cpp @@ -31,9 +31,9 @@ #include "array.h" #include "core/containers/hashfuncs.h" +#include "core/containers/vector.h" #include "core/object/object.h" #include "core/variant/variant.h" -#include "core/containers/vector.h" class ArrayPrivate { public: @@ -117,16 +117,25 @@ bool Array::operator==(const Array &p_array) const { } uint32_t Array::hash() const { + return recursive_hash(0); +} + +uint32_t Array::recursive_hash(int p_recursion_count) const { + ERR_FAIL_COND_V_MSG(p_recursion_count > MAX_RECURSION, 0, "Max recursion reached"); + p_recursion_count++; + uint32_t h = hash_murmur3_one_32(0); for (int i = 0; i < _p->array.size(); i++) { - h = hash_murmur3_one_32(_p->array[i].hash(), h); + h = hash_murmur3_one_32(_p->array[i].recursive_hash(p_recursion_count), h); } return hash_fmix32(h); } + void Array::operator=(const Array &p_array) { _ref(p_array); } + void Array::push_back(const Variant &p_value) { _p->array.push_back(p_value); } diff --git a/core/variant/array.h b/core/variant/array.h index 002404a47..1a07a8fb7 100644 --- a/core/variant/array.h +++ b/core/variant/array.h @@ -59,6 +59,7 @@ public: bool operator==(const Array &p_array) const; uint32_t hash() const; + uint32_t recursive_hash(int p_recursion_count) const; void operator=(const Array &p_array); void push_back(const Variant &p_value); diff --git a/core/variant/dictionary.cpp b/core/variant/dictionary.cpp index 1ad06b312..19ba54a08 100644 --- a/core/variant/dictionary.cpp +++ b/core/variant/dictionary.cpp @@ -221,12 +221,20 @@ void Dictionary::_unref() const { } _p = nullptr; } + uint32_t Dictionary::hash() const { + return recursive_hash(0); +} + +uint32_t Dictionary::recursive_hash(int p_recursion_count) const { + ERR_FAIL_COND_V_MSG(p_recursion_count > MAX_RECURSION, 0, "Max recursion reached"); + p_recursion_count++; + uint32_t h = hash_murmur3_one_32(Variant::DICTIONARY); for (OrderedHashMap::Element E = _p->variant_map.front(); E; E = E.next()) { - h = hash_murmur3_one_32(E.key().hash(), h); - h = hash_murmur3_one_32(E.value().hash(), h); + h = hash_murmur3_one_32(E.key().recursive_hash(p_recursion_count), h); + h = hash_murmur3_one_32(E.value().recursive_hash(p_recursion_count), h); } return hash_fmix32(h); diff --git a/core/variant/dictionary.h b/core/variant/dictionary.h index dbfc7756f..1064aad56 100644 --- a/core/variant/dictionary.h +++ b/core/variant/dictionary.h @@ -74,6 +74,7 @@ public: bool operator!=(const Dictionary &p_dictionary) const; uint32_t hash() const; + uint32_t recursive_hash(int p_recursion_count) const; void operator=(const Dictionary &p_dictionary); const Variant *next(const Variant *p_key = nullptr) const; diff --git a/core/variant/variant.cpp b/core/variant/variant.cpp index 304a1ea45..84af5f1b0 100644 --- a/core/variant/variant.cpp +++ b/core/variant/variant.cpp @@ -3224,6 +3224,10 @@ Variant::~Variant() { }*/ uint32_t Variant::hash() const { + return recursive_hash(0); +} + +uint32_t Variant::recursive_hash(int p_recursion_count) const { switch (type) { case NIL: { return 0; @@ -3376,13 +3380,13 @@ uint32_t Variant::hash() const { return reinterpret_cast(_data._mem)->hash(); } break; case DICTIONARY: { - return reinterpret_cast(_data._mem)->hash(); + return reinterpret_cast(_data._mem)->recursive_hash(p_recursion_count); } break; case ARRAY: { const Array &arr = *reinterpret_cast(_data._mem); - return arr.hash(); + return arr.recursive_hash(p_recursion_count); } break; - + case POOL_BYTE_ARRAY: { const PoolVector &arr = *reinterpret_cast *>(_data._mem); int len = arr.size(); diff --git a/core/variant/variant.h b/core/variant/variant.h index a997095eb..38719e391 100644 --- a/core/variant/variant.h +++ b/core/variant/variant.h @@ -464,6 +464,7 @@ public: bool operator!=(const Variant &p_variant) const; bool operator<(const Variant &p_variant) const; uint32_t hash() const; + uint32_t recursive_hash(int p_recursion_count) const; bool hash_compare(const Variant &p_variant) const; bool booleanize() const;