From 964c44cdcd6be5f39aed1aeda9c305803eb3b25f Mon Sep 17 00:00:00 2001 From: Hodlinator <172445034+hodlinator@users.noreply.github.com> Date: Wed, 25 Jun 2025 14:17:14 +0200 Subject: [PATCH] test(miniscript): Prove avoidance of stack overflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Can be tested through emptying the function body of ~Node() or replacing Clone() implementation with naive version: ```C++ Node Clone() const { std::vector new_subs; new_subs.reserve(subs.size()); for (const Node& child : subs) { new_subs.push_back(child.Clone()); } return Node{internal::NoDupCheck{}, m_script_ctx, fragment, std::move(new_subs), keys, data, k}; } ``` Co-authored-by: Lőrinc --- src/test/miniscript_tests.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/test/miniscript_tests.cpp b/src/test/miniscript_tests.cpp index 0cd5b62f7de..757f89b63bc 100644 --- a/src/test/miniscript_tests.cpp +++ b/src/test/miniscript_tests.cpp @@ -727,4 +727,25 @@ BOOST_AUTO_TEST_CASE(fixed_tests) g_testdata.reset(); } +// Confirm that ~Node(), Node::Clone() and operator=(Node&&) are stack-safe. +BOOST_AUTO_TEST_CASE(node_deep_destruct) +{ + using miniscript::internal::NoDupCheck; + using miniscript::Fragment; + using NodeU32 = miniscript::Node; + + constexpr auto ctx{miniscript::MiniscriptContext::P2WSH}; + + NodeU32 root{NoDupCheck{}, ctx, Fragment::JUST_1}; + for (uint32_t i{0}; i < 200'000; ++i) { + root = NodeU32{NoDupCheck{}, ctx, Fragment::WRAP_S, Vector(std::move(root))}; + } + BOOST_CHECK_EQUAL(root.ScriptSize(), 200'001); + + auto clone{root.Clone()}; + BOOST_CHECK_EQUAL(clone.ScriptSize(), root.ScriptSize()); + + clone = std::move(root); +} + BOOST_AUTO_TEST_SUITE_END()