From 8b1e297fc6567ead2c400199348d89e17b552899 Mon Sep 17 00:00:00 2001 From: Hein-Pieter van Braam-Stewart Date: Sat, 20 Apr 2019 01:57:29 +0200 Subject: [PATCH] Don't crash on printing nested types When adding an Array or Dictionary to itself operator String() got in an infinite loop. This commit adds a stack to operator String() (Through the use of a new 'stringify method'). This stack keeps track of all unique Arrays and Dictionaries it has seen. When a duplicate is found only a static string is printed '[...]' or '{...}'. This mirror Python's behavior in a similar case. --- core/array.cpp | 4 ++++ core/array.h | 2 ++ core/dictionary.cpp | 4 ++++ core/dictionary.h | 2 ++ core/list.h | 4 ++++ core/ordered_hash_map.h | 4 ++++ core/variant.cpp | 27 +++++++++++++++++++++++---- core/variant.h | 1 + 8 files changed, 44 insertions(+), 4 deletions(-) diff --git a/core/array.cpp b/core/array.cpp index 649e610a69b..65934d6ec92 100644 --- a/core/array.cpp +++ b/core/array.cpp @@ -401,6 +401,10 @@ Variant Array::max() const { return maxval; } +const void *Array::id() const { + return _p->array.ptr(); +} + Array::Array(const Array &p_from) { _p = NULL; diff --git a/core/array.h b/core/array.h index 6158db40653..d4e937a486b 100644 --- a/core/array.h +++ b/core/array.h @@ -94,6 +94,8 @@ public: Variant min() const; Variant max() const; + const void *id() const; + Array(const Array &p_from); Array(); ~Array(); diff --git a/core/dictionary.cpp b/core/dictionary.cpp index bea0997cc9e..5e4dfb9a5af 100644 --- a/core/dictionary.cpp +++ b/core/dictionary.cpp @@ -270,6 +270,10 @@ void Dictionary::operator=(const Dictionary &p_dictionary) { _ref(p_dictionary); } +const void *Dictionary::id() const { + return _p->variant_map.id(); +} + Dictionary::Dictionary(const Dictionary &p_from) { _p = NULL; _ref(p_from); diff --git a/core/dictionary.h b/core/dictionary.h index eab7354cef5..b68d3f57377 100644 --- a/core/dictionary.h +++ b/core/dictionary.h @@ -82,6 +82,8 @@ public: Dictionary duplicate(bool p_deep = false) const; + const void *id() const; + Dictionary(const Dictionary &p_from); Dictionary(); ~Dictionary(); diff --git a/core/list.h b/core/list.h index c26aad6463c..c21c20ba34a 100644 --- a/core/list.h +++ b/core/list.h @@ -691,6 +691,10 @@ public: memdelete_arr(aux_buffer); } + const void *id() const { + return (void *)_data; + } + /** * copy constructor for the list */ diff --git a/core/ordered_hash_map.h b/core/ordered_hash_map.h index 09d43d67974..2c18de92be4 100644 --- a/core/ordered_hash_map.h +++ b/core/ordered_hash_map.h @@ -274,6 +274,10 @@ public: inline bool empty() const { return list.empty(); } inline int size() const { return list.size(); } + const void *id() const { + return list.id(); + } + void clear() { map.clear(); list.clear(); diff --git a/core/variant.cpp b/core/variant.cpp index 6c54faf233e..1bc3cff505a 100644 --- a/core/variant.cpp +++ b/core/variant.cpp @@ -1415,7 +1415,12 @@ struct _VariantStrPair { }; Variant::operator String() const { + List stack; + return stringify(stack); +} + +String Variant::stringify(List &stack) const { switch (type) { case NIL: return "Null"; @@ -1467,6 +1472,12 @@ Variant::operator String() const { case DICTIONARY: { const Dictionary &d = *reinterpret_cast(_data._mem); + if (stack.find(d.id())) { + return "{...}"; + } + + stack.push_back(d.id()); + //const String *K=NULL; String str("{"); List keys; @@ -1477,8 +1488,9 @@ Variant::operator String() const { for (List::Element *E = keys.front(); E; E = E->next()) { _VariantStrPair sp; - sp.key = String(E->get()); - sp.value = d[E->get()]; + sp.key = E->get().stringify(stack); + sp.value = d[E->get()].stringify(stack); + pairs.push_back(sp); } @@ -1561,12 +1573,19 @@ Variant::operator String() const { case ARRAY: { Array arr = operator Array(); + if (stack.find(arr.id())) { + return "[...]"; + } + stack.push_back(arr.id()); + String str("["); for (int i = 0; i < arr.size(); i++) { if (i) str += ", "; - str += String(arr[i]); - }; + + str += arr[i].stringify(stack); + } + str += "]"; return str; diff --git a/core/variant.h b/core/variant.h index 9215d15bf05..5151262f278 100644 --- a/core/variant.h +++ b/core/variant.h @@ -401,6 +401,7 @@ public: bool hash_compare(const Variant &p_variant) const; bool booleanize() const; + String stringify(List &stack) const; void static_assign(const Variant &p_variant); static void get_constructor_list(Variant::Type p_type, List *p_list);