summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/context.cc20
-rw-r--r--src/context.h2
-rw-r--r--testdata/scad/misc/recursion-tests.scad2
-rw-r--r--tests/CMakeLists.txt3
-rw-r--r--tests/regression/echotest/recursion-tests-expected.txt2
5 files changed, 26 insertions, 3 deletions
diff --git a/src/context.cc b/src/context.cc
index f48cd86..a2a8d13 100644
--- a/src/context.cc
+++ b/src/context.cc
@@ -43,6 +43,7 @@ std::vector<const Context*> Context::ctx_stack;
Context::Context(const Context *parent, const Module *library)
: parent(parent), inst_p(NULL)
{
+ if (parent) recursioncount = parent->recursioncount;
ctx_stack.push_back(this);
if (parent) document_path = parent->document_path;
if (library) {
@@ -130,10 +131,26 @@ Value Context::lookup_variable(const std::string &name, bool silent) const
return Value();
}
+class RecursionGuard
+{
+public:
+ RecursionGuard(const Context &c, const std::string &name) : c(c), name(name) { c.recursioncount[name]++; }
+ ~RecursionGuard() { if (--c.recursioncount[name] == 0) c.recursioncount.erase(name); }
+ bool recursion_detected() const { return (c.recursioncount[name] > 100); }
+private:
+ const Context &c;
+ const std::string &name;
+};
+
Value Context::evaluate_function(const std::string &name,
const std::vector<std::string> &argnames,
const std::vector<Value> &argvalues) const
{
+ RecursionGuard g(*this, name);
+ if (g.recursion_detected()) {
+ PRINTB("Recursion detected calling function '%s'", name);
+ return Value();
+ }
if (this->functions_p && this->functions_p->find(name) != this->functions_p->end())
return this->functions_p->find(name)->second->evaluate(this, argnames, argvalues);
if (this->usedlibs_p) {
@@ -144,8 +161,7 @@ Value Context::evaluate_function(const std::string &name,
}
}
}
- if (this->parent)
- return this->parent->evaluate_function(name, argnames, argvalues);
+ if (this->parent) return this->parent->evaluate_function(name, argnames, argvalues);
PRINTB("WARNING: Ignoring unknown function '%s'.", name);
return Value();
}
diff --git a/src/context.h b/src/context.h
index f085e01..de5f1ca 100644
--- a/src/context.h
+++ b/src/context.h
@@ -41,6 +41,8 @@ public:
static std::vector<const Context*> ctx_stack;
+ mutable unordered_map<std::string, int> recursioncount;
+
private:
typedef unordered_map<std::string, Value> ValueMap;
ValueMap constants;
diff --git a/testdata/scad/misc/recursion-tests.scad b/testdata/scad/misc/recursion-tests.scad
new file mode 100644
index 0000000..2a07b91
--- /dev/null
+++ b/testdata/scad/misc/recursion-tests.scad
@@ -0,0 +1,2 @@
+function crash() = crash();
+echo(crash());
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 33f3547..68083ce 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -704,7 +704,8 @@ list(APPEND ECHO_FILES ${FUNCTION_FILES}
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/string-test.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/string-indexing.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/vector-values.scad
- ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/search-tests.scad)
+ ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/search-tests.scad
+ ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/recursion-tests.scad)
list(APPEND DUMPTEST_FILES ${MINIMAL_FILES} ${FEATURES_FILES} ${EXAMPLE_FILES})
list(APPEND DUMPTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/escape-test.scad
diff --git a/tests/regression/echotest/recursion-tests-expected.txt b/tests/regression/echotest/recursion-tests-expected.txt
new file mode 100644
index 0000000..f4897ee
--- /dev/null
+++ b/tests/regression/echotest/recursion-tests-expected.txt
@@ -0,0 +1,2 @@
+Recursion detected calling function 'crash'
+ECHO: undef
contact: Jan Huwald // Impressum