Handle cycles when printing a value

So this no longer crashes with a stack overflow:

  nix-instantiate -E --eval 'let as = { x = as; }; in as'

Instead it prints:

  { x = { x = <CYCLE>; }; }
This commit is contained in:
Eelco Dolstra 2014-09-22 14:59:37 +02:00
parent a54c263402
commit 022618c794

View file

@ -38,8 +38,14 @@ void Bindings::sort()
} }
std::ostream & operator << (std::ostream & str, const Value & v) static void printValue(std::ostream & str, std::set<const Value *> & seen, const Value & v)
{ {
if (seen.find(&v) != seen.end()) {
str << "<CYCLE>";
return;
}
seen.insert(&v);
switch (v.type) { switch (v.type) {
case tInt: case tInt:
str << v.integer; str << v.integer;
@ -69,15 +75,20 @@ std::ostream & operator << (std::ostream & str, const Value & v)
Sorted sorted; Sorted sorted;
foreach (Bindings::iterator, i, *v.attrs) foreach (Bindings::iterator, i, *v.attrs)
sorted[i->name] = i->value; sorted[i->name] = i->value;
foreach (Sorted::iterator, i, sorted) for (auto & i : sorted) {
str << i->first << " = " << *i->second << "; "; str << i.first << " = ";
printValue(str, seen, *i.second);
str << "; ";
}
str << "}"; str << "}";
break; break;
} }
case tList: case tList:
str << "[ "; str << "[ ";
for (unsigned int n = 0; n < v.list.length; ++n) for (unsigned int n = 0; n < v.list.length; ++n) {
str << *v.list.elems[n] << " "; printValue(str, seen, *v.list.elems[n]);
str << " ";
}
str << "]"; str << "]";
break; break;
case tThunk: case tThunk:
@ -96,6 +107,13 @@ std::ostream & operator << (std::ostream & str, const Value & v)
default: default:
throw Error("invalid value"); throw Error("invalid value");
} }
}
std::ostream & operator << (std::ostream & str, const Value & v)
{
std::set<const Value *> seen;
printValue(str, seen, v);
return str; return str;
} }