diff --git a/src/bt_factory.cpp b/src/bt_factory.cpp index 9c47bd331..f772a37be 100644 --- a/src/bt_factory.cpp +++ b/src/bt_factory.cpp @@ -20,6 +20,7 @@ #include #include +#include namespace BT { @@ -755,6 +756,13 @@ void Tree::applyVisitor(const std::function& visitor) uint16_t Tree::getUID() { + // UIDs are 16 bits wide (and serialized as such by Groot2 and the loggers): + // wrapping around would silently give two nodes the same UID. + if(uid_counter_ == std::numeric_limits::max()) + { + throw RuntimeError("Tree::getUID(): too many nodes, a tree can't have more than ", + std::to_string(std::numeric_limits::max()), " nodes"); + } auto uid = ++uid_counter_; return uid; } diff --git a/tests/gtest_factory.cpp b/tests/gtest_factory.cpp index 2c257b5b2..23542b703 100644 --- a/tests/gtest_factory.cpp +++ b/tests/gtest_factory.cpp @@ -1,6 +1,7 @@ #include "behaviortree_cpp/xml_parsing.h" #include +#include #include #include #include @@ -777,3 +778,18 @@ TEST(BehaviorTreeFactory, MalformedXML_UnknownNodeType) BehaviorTreeFactory factory; EXPECT_THROW((void)factory.createTreeFromText(xml), RuntimeError); } + +TEST(BehaviorTreeFactory, TooManyNodesForUID) +{ + // UIDs are 16 bits wide. Past 65535 nodes the counter used to wrap around + // and the next nodes got the same UID (and path) as the first ones. + Tree tree; + std::set uids; + for(int i = 0; i < 65535; i++) + { + uids.insert(tree.getUID()); + } + EXPECT_EQ(uids.size(), 65535u); + EXPECT_EQ(uids.count(0), 0u); + EXPECT_THROW((void)tree.getUID(), RuntimeError); +}