Skip to content

Commit 7f0576b

Browse files
throw instead of wrapping the 16-bit UID counter in Tree::getUID (#1244)
Tree::getUID() incremented a uint16_t counter, so in a tree with more than 65535 nodes the UIDs wrapped around and collided (node 65537 got the UID of node 1), confusing Groot2, the loggers and TreeObserver, which key on UID. It now throws a RuntimeError when the counter is exhausted. Behavior change: creating a tree with more than 65535 nodes now throws instead of succeeding with duplicate UIDs.
1 parent d20f628 commit 7f0576b

2 files changed

Lines changed: 24 additions & 0 deletions

File tree

‎src/bt_factory.cpp‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#include <filesystem>
2222
#include <functional>
23+
#include <limits>
2324

2425
namespace BT
2526
{
@@ -755,6 +756,13 @@ void Tree::applyVisitor(const std::function<void(TreeNode*)>& visitor)
755756

756757
uint16_t Tree::getUID()
757758
{
759+
// UIDs are 16 bits wide (and serialized as such by Groot2 and the loggers):
760+
// wrapping around would silently give two nodes the same UID.
761+
if(uid_counter_ == std::numeric_limits<uint16_t>::max())
762+
{
763+
throw RuntimeError("Tree::getUID(): too many nodes, a tree can't have more than ",
764+
std::to_string(std::numeric_limits<uint16_t>::max()), " nodes");
765+
}
758766
auto uid = ++uid_counter_;
759767
return uid;
760768
}

‎tests/gtest_factory.cpp‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include "behaviortree_cpp/xml_parsing.h"
22

33
#include <filesystem>
4+
#include <set>
45
#include <string>
56
#include <utility>
67
#include <vector>
@@ -795,3 +796,18 @@ TEST(BehaviorTreeFactory, MalformedXML_UnknownNodeType)
795796
BehaviorTreeFactory factory;
796797
EXPECT_THROW((void)factory.createTreeFromText(xml), RuntimeError);
797798
}
799+
800+
TEST(BehaviorTreeFactory, TooManyNodesForUID)
801+
{
802+
// UIDs are 16 bits wide. Past 65535 nodes the counter used to wrap around
803+
// and the next nodes got the same UID (and path) as the first ones.
804+
Tree tree;
805+
std::set<uint16_t> uids;
806+
for(int i = 0; i < 65535; i++)
807+
{
808+
uids.insert(tree.getUID());
809+
}
810+
EXPECT_EQ(uids.size(), 65535u);
811+
EXPECT_EQ(uids.count(0), 0u);
812+
EXPECT_THROW((void)tree.getUID(), RuntimeError);
813+
}

0 commit comments

Comments
 (0)