From 022618c794f64ea354e7c9e166f3c8fc1654c470 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 22 Sep 2014 14:59:37 +0200 Subject: [PATCH] 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 = ; }; } --- src/libexpr/eval.cc | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index bd49cec4f..1dab5ceff 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -38,8 +38,14 @@ void Bindings::sort() } -std::ostream & operator << (std::ostream & str, const Value & v) +static void printValue(std::ostream & str, std::set & seen, const Value & v) { + if (seen.find(&v) != seen.end()) { + str << ""; + return; + } + seen.insert(&v); + switch (v.type) { case tInt: str << v.integer; @@ -69,15 +75,20 @@ std::ostream & operator << (std::ostream & str, const Value & v) Sorted sorted; foreach (Bindings::iterator, i, *v.attrs) sorted[i->name] = i->value; - foreach (Sorted::iterator, i, sorted) - str << i->first << " = " << *i->second << "; "; + for (auto & i : sorted) { + str << i.first << " = "; + printValue(str, seen, *i.second); + str << "; "; + } str << "}"; break; } case tList: str << "[ "; - for (unsigned int n = 0; n < v.list.length; ++n) - str << *v.list.elems[n] << " "; + for (unsigned int n = 0; n < v.list.length; ++n) { + printValue(str, seen, *v.list.elems[n]); + str << " "; + } str << "]"; break; case tThunk: @@ -96,6 +107,13 @@ std::ostream & operator << (std::ostream & str, const Value & v) default: throw Error("invalid value"); } +} + + +std::ostream & operator << (std::ostream & str, const Value & v) +{ + std::set seen; + printValue(str, seen, v); return str; }