From 069d106ab45fdb6fed675eb71aa85c774a2bb998 Mon Sep 17 00:00:00 2001 From: Nathan Ridge Date: Thu, 26 Nov 2015 20:46:50 -0500 Subject: [PATCH] Bug 479138 - Impose a global template instantiation depth limit This protects against rogue template metaprograms that don't terminate. Change-Id: I9558ceaaed17baddbed84aac67a3c72397b62b64 Signed-off-by: Nathan Ridge --- .../tests/IndexCPPTemplateResolutionTest.java | 23 +++++++++++++++++++ .../parser/cpp/semantics/CPPTemplates.java | 20 ++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPTemplateResolutionTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPTemplateResolutionTest.java index fdd71ce558f..47d432e7b1a 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPTemplateResolutionTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexCPPTemplateResolutionTest.java @@ -2847,4 +2847,27 @@ public class IndexCPPTemplateResolutionTest extends IndexBindingResolutionTestBa // intermediate results cannot be collapsed into a single value. checkBindings(); } + + // template struct _GcdX { + // static const long value = _GcdX<_Ax - 1>::value; + // }; + // + // template struct R { + // static const long value = _Ax; + // }; + // + // template struct Operation { + // static const long _N1 = _R1::value; + // typedef R<_GcdX<_N1>::value> value; + // }; + // + // typedef Operation< R<1> >::value MYTYPE; + + // // empty file + // // special:allowRecursionBindings + public void testRecursiveTemplateInstantiation_479138c() throws Exception { + // This tests that a template metaprogram that doesn't terminate at all + // (e.g. because the author omitted a base case) doesn't cause a stack overflow. + checkBindings(); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java index f58bd1af778..cdb2715b7dc 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPTemplates.java @@ -121,6 +121,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPAliasTemplateInstance; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPArrayType; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassInstance; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassSpecialization; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassSpecialization.RecursionResolvingBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassTemplatePartialSpecialization; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassTemplatePartialSpecializationSpecialization; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassTemplateSpecialization; @@ -195,6 +196,15 @@ public class CPPTemplates { static final int PACK_SIZE_NOT_FOUND = Integer.MAX_VALUE; static enum TypeSelection { PARAMETERS, RETURN_TYPE, PARAMETERS_AND_RETURN_TYPE } + + // Infrastructure to protect against rogue template metaprograms that don't terminate. + private static final int TEMPLATE_INSTANTIATION_DEPTH_LIMIT = 256; + private static final ThreadLocal fTemplateInstantiationDepth = new ThreadLocal() { + @Override + protected Integer initialValue() { + return 0; + } + }; /** * Instantiates a class template with the given arguments. May return {@code null}. @@ -901,6 +911,13 @@ public class CPPTemplates { public static IBinding createSpecialization(ICPPClassSpecialization owner, IBinding decl, IASTNode point) { IBinding spec = null; final ICPPTemplateParameterMap tpMap= owner.getTemplateParameterMap(); + // Guard against infinite recursion during template instantiation with a depth limit. + int instantiationDepth = fTemplateInstantiationDepth.get(); + if (instantiationDepth > TEMPLATE_INSTANTIATION_DEPTH_LIMIT) { + return RecursionResolvingBinding.createFor(decl, point); + } + // Increment the instantiation depth for the duration of this call. + fTemplateInstantiationDepth.set(instantiationDepth + 1); try { if (decl instanceof ICPPClassTemplatePartialSpecialization) { try { @@ -1007,6 +1024,9 @@ public class CPPTemplates { } } catch (DOMException e) { CCorePlugin.log(e); + } finally { + // Restore original instantiation depth. + fTemplateInstantiationDepth.set(instantiationDepth); } return spec; }