Introduction

Valgrind is a programming tool used for memory debugging. In the ros wiki (accessed Aug 2023), the use of using roslaunch with valgrind is described. This post will demonstrate the use of valgrind with a rosnode via roslaunch.

The results of this post was obtained on Ubuntu 20.04 with ROS Noetic.

Setup

First, you need to have valgrind installed. On Ubuntu, you can install valgrind with:

sudo apt install valgrind

Roslaunch File

Using roslaunch, one simply needs to include valgrind in the launch-prefix tag for the node to be launched with valgrind. The segfault-example-node will be used as an example node to be launched.

<launch>
  <node pkg="ros_segfault_example" type="segfault_example_node" name="segfault_example_node"
    launch-prefix="valgrind" />
</launch>

Running

Launching the rosnode via roslaunch, in addition to the usual roslaunch printout, the following also appears:

==7169== Memcheck, a memory error detector
==7169== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==7169== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==7169== Command: /home/bronya/catkin_ws/devel/lib/ros_segfault_example/segfault_example_node __name:=segfault_example_node __log:=/home/bronya/.ros/log/94e98a06-41a1-11ee-a929-f3b6ab2164c3/segfault_example_node-1.log
==7169== 

This indicates that valgrind is indeed running with the target executable.

Debugging

In my case, I will induce a segfault. After a segfault was induced, the following can be found near the top of the printout:

...
==7169== Invalid read of size 4
==7169==    at 0x128959: channelCB1(boost::shared_ptr<std_msgs::String_<std::allocator<void> > const> const&) (segfault_example_node.cpp:24)
==7169==    by 0x12ED0B: boost::detail::function::void_function_invoker1<void (*)(boost::shared_ptr<std_msgs::String_<std::allocator<void> > const> const&), void, boost::shared_ptr<std_msgs::String_<std::allocator<void> > const> const&>::invoke(boost::detail::function::function_buffer&, boost::shared_ptr<std_msgs::String_<std::allocator<void> > const> const&) (function_template.hpp:117)
==7169==    by 0x130D6F: boost::function1<void, boost::shared_ptr<std_msgs::String_<std::allocator<void> > const> const&>::operator()(boost::shared_ptr<std_msgs::String_<std::allocator<void> > const> const&) const (function_template.hpp:763)
==7169==    by 0x1303B5: boost::detail::function::void_function_obj_invoker1<boost::function<void (boost::shared_ptr<std_msgs::String_<std::allocator<void> > const> const&)>, void, boost::shared_ptr<std_msgs::String_<std::allocator<void> > const> >::invoke(boost::detail::function::function_buffer&, boost::shared_ptr<std_msgs::String_<std::allocator<void> > const>) (function_template.hpp:158)
==7169==    by 0x132A50: boost::function1<void, boost::shared_ptr<std_msgs::String_<std::allocator<void> > const> >::operator()(boost::shared_ptr<std_msgs::String_<std::allocator<void> > const>) const (function_template.hpp:763)
==7169==    by 0x132290: ros::SubscriptionCallbackHelperT<boost::shared_ptr<std_msgs::String_<std::allocator<void> > const> const&, void>::call(ros::SubscriptionCallbackHelperCallParams&) (subscription_callback_helper.h:144)
==7169==    by 0x49A2138: ros::SubscriptionQueue::call() (in /opt/ros/noetic/lib/libroscpp.so)
==7169==    by 0x4950171: ros::CallbackQueue::callOneCB(ros::CallbackQueue::TLS*) (in /opt/ros/noetic/lib/libroscpp.so)
==7169==    by 0x4951882: ros::CallbackQueue::callAvailable(ros::WallDuration) (in /opt/ros/noetic/lib/libroscpp.so)
==7169==    by 0x49A4FCE: ros::SingleThreadedSpinner::spin(ros::CallbackQueue*) (in /opt/ros/noetic/lib/libroscpp.so)
==7169==    by 0x498D21E: ros::spin() (in /opt/ros/noetic/lib/libroscpp.so)
==7169==    by 0x128CDE: main (segfault_example_node.cpp:36)
...

Indeed, similar to the example in gdb with ros, it also points to the fact that line 24 was problematic. In particular, I was trying to access element 0 of a std::vector of length 0 and capacity 0.

Conclusion

In this post, I’ve demonstrated the simple use of valgrind with ROS, via integrating in via roslaunch. Valgrind is much more powerful than the example I’ve shown here, and it is often using for debugging memory issues and profiling. Indeed, if you suspect memory leak, you can start profiling memory leak by adding arguments to the launch-prefix like so:

<launch>
  <node pkg="node_package" type="example_node" name="example_node_name"
    launch-prefix="valgrind  --tool=memcheck --leak-check=yes" />
</launch>

Comments or discussions may be posted here.