ソースを参照

[3.x] Core: Add recursion level check for `Array` and `Dictionary` hashing

Danil Alexeev 2 年 前
コミット
68e8c1bb8f
6 ファイル変更29 行追加8 行削除
  1. 10 1
      core/array.cpp
  2. 1 0
      core/array.h
  3. 10 2
      core/dictionary.cpp
  4. 1 0
      core/dictionary.h
  5. 6 5
      core/variant.cpp
  6. 1 0
      core/variant.h

+ 10 - 1
core/array.cpp

@@ -118,16 +118,25 @@ bool Array::operator==(const Array &p_array) const {
 }
 }
 
 
 uint32_t Array::hash() 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_djb2_one_32(0);
 	uint32_t h = hash_djb2_one_32(0);
 
 
 	for (int i = 0; i < _p->array.size(); i++) {
 	for (int i = 0; i < _p->array.size(); i++) {
-		h = hash_djb2_one_32(_p->array[i].hash(), h);
+		h = hash_djb2_one_32(_p->array[i].recursive_hash(p_recursion_count), h);
 	}
 	}
 	return h;
 	return h;
 }
 }
+
 void Array::operator=(const Array &p_array) {
 void Array::operator=(const Array &p_array) {
 	_ref(p_array);
 	_ref(p_array);
 }
 }
+
 void Array::push_back(const Variant &p_value) {
 void Array::push_back(const Variant &p_value) {
 	_p->array.push_back(p_value);
 	_p->array.push_back(p_value);
 }
 }

+ 1 - 0
core/array.h

@@ -60,6 +60,7 @@ public:
 	bool operator==(const Array &p_array) const;
 	bool operator==(const Array &p_array) const;
 
 
 	uint32_t hash() const;
 	uint32_t hash() const;
+	uint32_t recursive_hash(int p_recursion_count) const;
 	void operator=(const Array &p_array);
 	void operator=(const Array &p_array);
 
 
 	void push_back(const Variant &p_value);
 	void push_back(const Variant &p_value);

+ 10 - 2
core/dictionary.cpp

@@ -221,12 +221,20 @@ void Dictionary::_unref() const {
 	}
 	}
 	_p = nullptr;
 	_p = nullptr;
 }
 }
+
 uint32_t Dictionary::hash() const {
 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_djb2_one_32(Variant::DICTIONARY);
 	uint32_t h = hash_djb2_one_32(Variant::DICTIONARY);
 
 
 	for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) {
 	for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) {
-		h = hash_djb2_one_32(E.key().hash(), h);
-		h = hash_djb2_one_32(E.value().hash(), h);
+		h = hash_djb2_one_32(E.key().recursive_hash(p_recursion_count), h);
+		h = hash_djb2_one_32(E.value().recursive_hash(p_recursion_count), h);
 	}
 	}
 
 
 	return h;
 	return h;

+ 1 - 0
core/dictionary.h

@@ -75,6 +75,7 @@ public:
 	bool operator!=(const Dictionary &p_dictionary) const;
 	bool operator!=(const Dictionary &p_dictionary) const;
 
 
 	uint32_t hash() const;
 	uint32_t hash() const;
+	uint32_t recursive_hash(int p_recursion_count) const;
 	void operator=(const Dictionary &p_dictionary);
 	void operator=(const Dictionary &p_dictionary);
 
 
 	const Variant *next(const Variant *p_key = nullptr) const;
 	const Variant *next(const Variant *p_key = nullptr) const;

+ 6 - 5
core/variant.cpp

@@ -2508,6 +2508,10 @@ Variant::~Variant() {
 }*/
 }*/
 
 
 uint32_t Variant::hash() const {
 uint32_t Variant::hash() const {
+	return recursive_hash(0);
+}
+
+uint32_t Variant::recursive_hash(int p_recursion_count) const {
 	switch (type) {
 	switch (type) {
 		case NIL: {
 		case NIL: {
 			return 0;
 			return 0;
@@ -2622,13 +2626,10 @@ uint32_t Variant::hash() const {
 			return reinterpret_cast<const NodePath *>(_data._mem)->hash();
 			return reinterpret_cast<const NodePath *>(_data._mem)->hash();
 		} break;
 		} break;
 		case DICTIONARY: {
 		case DICTIONARY: {
-			return reinterpret_cast<const Dictionary *>(_data._mem)->hash();
-
+			return reinterpret_cast<const Dictionary *>(_data._mem)->recursive_hash(p_recursion_count);
 		} break;
 		} break;
 		case ARRAY: {
 		case ARRAY: {
-			const Array &arr = *reinterpret_cast<const Array *>(_data._mem);
-			return arr.hash();
-
+			return reinterpret_cast<const Array *>(_data._mem)->recursive_hash(p_recursion_count);
 		} break;
 		} break;
 		case POOL_BYTE_ARRAY: {
 		case POOL_BYTE_ARRAY: {
 			const PoolVector<uint8_t> &arr = *reinterpret_cast<const PoolVector<uint8_t> *>(_data._mem);
 			const PoolVector<uint8_t> &arr = *reinterpret_cast<const PoolVector<uint8_t> *>(_data._mem);

+ 1 - 0
core/variant.h

@@ -413,6 +413,7 @@ public:
 	bool operator!=(const Variant &p_variant) const;
 	bool operator!=(const Variant &p_variant) const;
 	bool operator<(const Variant &p_variant) const;
 	bool operator<(const Variant &p_variant) const;
 	uint32_t hash() const;
 	uint32_t hash() const;
+	uint32_t recursive_hash(int p_recursion_count) const;
 
 
 	bool hash_compare(const Variant &p_variant) const;
 	bool hash_compare(const Variant &p_variant) const;
 	bool booleanize() const;
 	bool booleanize() const;