Repository navigation
reset a child's status when its halt() throws in ControlNode::haltChild - #1273
Conversation
Previously the child stayed RUNNING, so the next halt of the parent halted it again and threw a second time. When that happened inside ~Tree(), the process terminated. Callers still see the exception. This covers haltChild() and haltChildren(), which calls it. ControlNode::resetChildren() and DecoratorNode::resetChild() have the same pattern and are left for a follow-up.
The previous commit reset a child's status in ControlNode::haltChild() when
its halt() threw, so the next reset does not halt it again. But built-in
nodes halt their children through ControlNode::resetChildren() and
DecoratorNode::resetChild()/haltChild(), and Tree::haltTree() halts the root
directly: all of them go through TreeNode::haltNode() and kept the bug (the
node stays RUNNING, is halted a second time, and ~Tree() -> haltTree() throws
again from a destructor, i.e. std::terminate).
Put the guard in the single choke point, TreeNode::haltNode():
try { halt(); } catch(...) { resetStatus(); throw; }, and drop the
now-redundant try/catch in ControlNode::haltChild(). The exception still
propagates. The existing _onHalted post-condition code is unchanged.
Add tests with built-in parents (Sequence, RetryUntilSuccessful): haltTree()
throws once, every node is IDLE afterwards, a second haltTree() does not
throw and onHalted() is not called again. No ABI change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks @dvadovsz. The bug is real, but I pushed b1a3f86 on top of a merge of master. It moves the guard to that single point ( There's no ABI change; the edit is .cpp-only. One limit remains: the first throw inside I'll squash-merge once CI is green. #1229 can then drop its copy of the |
Take master's src/control_node.cpp and tests/gtest_halt_child.cpp (BehaviorTree#1273, b6709b6), which supersede this branch's copy of the haltChild fix (fbbcdd1): the status reset now lives in TreeNode::haltNode(). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01ME1hnSFSzibU5phxboGsjk
Split out of #1229, as requested in review.
ControlNode::haltChildnow resets the child's status before rethrowing an exception from the child'shalt(). Previously the child stayed RUNNING, so the next halt of the parent halted it again and threw a second time. When that happened inside~Tree(), the process terminated. Callers still see the exception.haltChildren()gets the fix throughhaltChild().tests/gtest_halt_child.cppadds a control node that halts its child throughhaltChild(), with a child whoseonHalted()throws. Without the fix the second halt callsonHalted()again and throws, the child is left RUNNING, and the test binary aborts instd::terminatewhen the tree is destroyed. With the fix it passes.ControlNode::resetChildren()andDecoratorNode::resetChild()have the same pattern. I left them out to keep this small and can add them here if you prefer.API/ABI: no signature changes.