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.
This commit is contained in:
Hein-Pieter van Braam-Stewart 2019-04-20 01:57:29 +02:00
parent 8e652a1400
commit 8b1e297fc6
8 changed files with 44 additions and 4 deletions

View File

@ -401,6 +401,10 @@ Variant Array::max() const {
return maxval; return maxval;
} }
const void *Array::id() const {
return _p->array.ptr();
}
Array::Array(const Array &p_from) { Array::Array(const Array &p_from) {
_p = NULL; _p = NULL;

View File

@ -94,6 +94,8 @@ public:
Variant min() const; Variant min() const;
Variant max() const; Variant max() const;
const void *id() const;
Array(const Array &p_from); Array(const Array &p_from);
Array(); Array();
~Array(); ~Array();

View File

@ -270,6 +270,10 @@ void Dictionary::operator=(const Dictionary &p_dictionary) {
_ref(p_dictionary); _ref(p_dictionary);
} }
const void *Dictionary::id() const {
return _p->variant_map.id();
}
Dictionary::Dictionary(const Dictionary &p_from) { Dictionary::Dictionary(const Dictionary &p_from) {
_p = NULL; _p = NULL;
_ref(p_from); _ref(p_from);

View File

@ -82,6 +82,8 @@ public:
Dictionary duplicate(bool p_deep = false) const; Dictionary duplicate(bool p_deep = false) const;
const void *id() const;
Dictionary(const Dictionary &p_from); Dictionary(const Dictionary &p_from);
Dictionary(); Dictionary();
~Dictionary(); ~Dictionary();

View File

@ -691,6 +691,10 @@ public:
memdelete_arr(aux_buffer); memdelete_arr(aux_buffer);
} }
const void *id() const {
return (void *)_data;
}
/** /**
* copy constructor for the list * copy constructor for the list
*/ */

View File

@ -274,6 +274,10 @@ public:
inline bool empty() const { return list.empty(); } inline bool empty() const { return list.empty(); }
inline int size() const { return list.size(); } inline int size() const { return list.size(); }
const void *id() const {
return list.id();
}
void clear() { void clear() {
map.clear(); map.clear();
list.clear(); list.clear();

View File

@ -1415,7 +1415,12 @@ struct _VariantStrPair {
}; };
Variant::operator String() const { Variant::operator String() const {
List<const void *> stack;
return stringify(stack);
}
String Variant::stringify(List<const void *> &stack) const {
switch (type) { switch (type) {
case NIL: return "Null"; case NIL: return "Null";
@ -1467,6 +1472,12 @@ Variant::operator String() const {
case DICTIONARY: { case DICTIONARY: {
const Dictionary &d = *reinterpret_cast<const Dictionary *>(_data._mem); const Dictionary &d = *reinterpret_cast<const Dictionary *>(_data._mem);
if (stack.find(d.id())) {
return "{...}";
}
stack.push_back(d.id());
//const String *K=NULL; //const String *K=NULL;
String str("{"); String str("{");
List<Variant> keys; List<Variant> keys;
@ -1477,8 +1488,9 @@ Variant::operator String() const {
for (List<Variant>::Element *E = keys.front(); E; E = E->next()) { for (List<Variant>::Element *E = keys.front(); E; E = E->next()) {
_VariantStrPair sp; _VariantStrPair sp;
sp.key = String(E->get()); sp.key = E->get().stringify(stack);
sp.value = d[E->get()]; sp.value = d[E->get()].stringify(stack);
pairs.push_back(sp); pairs.push_back(sp);
} }
@ -1561,12 +1573,19 @@ Variant::operator String() const {
case ARRAY: { case ARRAY: {
Array arr = operator Array(); Array arr = operator Array();
if (stack.find(arr.id())) {
return "[...]";
}
stack.push_back(arr.id());
String str("["); String str("[");
for (int i = 0; i < arr.size(); i++) { for (int i = 0; i < arr.size(); i++) {
if (i) if (i)
str += ", "; str += ", ";
str += String(arr[i]);
}; str += arr[i].stringify(stack);
}
str += "]"; str += "]";
return str; return str;

View File

@ -401,6 +401,7 @@ public:
bool hash_compare(const Variant &p_variant) const; bool hash_compare(const Variant &p_variant) const;
bool booleanize() const; bool booleanize() const;
String stringify(List<const void *> &stack) const;
void static_assign(const Variant &p_variant); void static_assign(const Variant &p_variant);
static void get_constructor_list(Variant::Type p_type, List<MethodInfo> *p_list); static void get_constructor_list(Variant::Type p_type, List<MethodInfo> *p_list);