Legacy: STM32 assertion on TX timeout

Using legacy libuavcan and the stm32 baremetal driver, I am making a driver for a rangefinder. I have got everything to work as I like, except for if I start the program before connecting it to another CAN device (in my case a Pixhawk Cube). If I power up my rangefinder and stm32 disconnected it runs for about 1 second (aka my TxTimeout) and then throws the bellow assertion. Decreasing my TxTimeout makes the assertion pop up faster, and starting it plugged into the Pixhawk results in it working whether or not I disconnect it after a second or two, publishing my rangefinder data at ~30Hz.

assertion "used_blocks_ > 0" failed: file "../libuavcan/libuavcan/libuavcan/src/uc_dynamic_memory.cpp", line 29, function: virtual void uavcan::LimitedPoolAllocator::deallocate(const void*)

Any ideas on whats happening or how I could prevent this?

-Ian

As the assertion check suggests, you are dealing with a double-free problem. Try tracing your memory allocations (e.g., by printing via serial port or using GDB trace points) to see what is causing the problem.

Ah, meant to also post the stack trace. It seems to be within the TxQueue but I am still a bit lost.

Thread #1 [main] 1 [core: 0] (Suspended : Breakpoint)	
	_exit() at syscalls.c:66 0x8012b12	
	abort() at 0x8035cac	
	__assert_func() at 0x8035cd0	
	uavcan::LimitedPoolAllocator::deallocate() at uc_dynamic_memory.cpp:29 0x80220a2	
	uavcan::AvlTree<uavcan::CanTxQueueEntry>::deleteNode() at avl_tree.hpp:74 0x801c1aa	
	uavcan::AvlTree<uavcan::CanTxQueueEntry>::deleteFromList() at avl_tree.hpp:186 0x801c21a	
	uavcan::AvlTree<uavcan::CanTxQueueEntry>::removeNode() at avl_tree.hpp:267 0x801bcca	
	uavcan::CanTxQueue::searchForNonExpiredMax() at uc_can_io.cpp:175 0x801b03e	
	uavcan::CanTxQueue::searchForNonExpiredMax() at uc_can_io.cpp:179 0x801b064	
	uavcan::CanTxQueue::searchForNonExpiredMax() at uc_can_io.cpp:179 0x801b064	
	uavcan::CanTxQueue::searchForNonExpiredMax() at uc_can_io.cpp:179 0x801b064	
....
....
....
	uavcan::CanTxQueue::searchForNonExpiredMax() at uc_can_io.cpp:179 0x801b064
        uavcan::CanTxQueue::searchForNonExpiredMax() at uc_can_io.cpp:179 0x801b064	
	uavcan::CanTxQueue::searchForNonExpiredMax() at uc_can_io.cpp:179 0x801b064	
	uavcan::CanTxQueue::peek() at uc_can_io.cpp:144 0x801af16	
	uavcan::CanIOManager::receive() at uc_can_io.cpp:425 0x801b898	
	uavcan::Dispatcher::spin() at uc_dispatcher.cpp:228 0x801cb54	
	uavcan::Scheduler::spin() at uc_scheduler.cpp:169 0x801923c	
	uavcan::INode::spin() at abstract_node.hpp:76 0x80110dc	
	uavcan::Node<16384u>::spin() at node.hpp:133 0x80114c8	
	main() at main.cpp:46 0x80111cc	

Specifically in

uavcan::AvlTree<uavcan::CanTxQueueEntry>::Node* CanTxQueue::searchForNonExpiredMax(Node* n) {
    if (n == UAVCAN_NULLPTR) {
        return UAVCAN_NULLPTR;
    }

    const MonotonicTime timestamp = sysclock_.getMonotonic();

    while(n->data->isExpired(timestamp)) {
        remove(n->data);
        return searchForNonExpiredMax(root_);
    }

    while(n->right != UAVCAN_NULLPTR && n->right->data->isExpired(timestamp)) {
        CanTxQueueEntry* expiredEntry = n->data;
        n->right = this->AvlTree::removeNode(n, n->data); //assert is caused here.........
        CanTxQueueEntry::destroy(expiredEntry, allocator_);   
    }

    Node* r = searchForNonExpiredMax(n->right); //recusion making up most of the stack

    if (r != UAVCAN_NULLPTR) {
        return r;
    }

    return n;
}

You might have run into a banal stack overflow.