-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
Bug report
Required Info:
- Operating System:
- Ubuntu 18.04 bionic
- ROS2 Version:
- Current master head
- Version or commit hash:
- DDS implementation:
- Unrelated, not using nodes at all
Issue and analysis
I have an isolated unit test environment that is meant to test the algorithm used by the Smac hybrid astar planner.
A unit test in this environment is always throwing a 'vector::reserve' std::exception.
The exception is thrown at line 139 in nav2_smac_planner/collision_checker.hpp:
int angle_bin = theta / bin_size_;
geometry_msgs::msg::Point new_pt;
const nav2_costmap_2d::Footprint & oriented_footprint = oriented_footprints_[angle_bin];
nav2_costmap_2d::Footprint current_footprint;
current_footprint.reserve(oriented_footprint.size()); // exception is thrown here
The reserve fails here, because the angle_bin ends up being equal to oriented_footprints_.size(), which means that oriented_footprint.size() is memory garbage due to over indexing.
This happens because the passed in theta ends up being 72 due to an unfortunate chain of float precision errors. I am using default settings with 72 angle_quantization_bins, so the passed in theta should never reach 72 [0, 72).
The crash can be simply prevented by ensuring the index is not out of range:
const nav2_costmap_2d::Footprint & oriented_footprint = oriented_footprints_[angle_bin % oriented_footprints_.size()];
Further analysis
The following code in nav2_smac_planner/src/a_star.cpp is meant to ensure that the orientation is in the right range:
node->motion_table.state_space->interpolate(from(), to(), i / num_intervals, s());
reals = s.reals();
angle = reals[2] / node->motion_table.bin_size;
while (angle >= node->motion_table.num_angle_quantization_float) {
angle -= node->motion_table.num_angle_quantization_float;
}
while (angle < 0.0) {
angle += node->motion_table.num_angle_quantization_float;
}
Unfortunately with certain values this code fails to do its job.
In my test case the reals[2] ends up being a very tiny negative value: -1.2830684958942129e-08
So angle will be also a tiny negative value: -1.47028814e-07
When this tiny negative value is increased by node->motion_table.num_angle_quantization_float (72) it ends up rolling up to 72 due to the limited precision, which is not valid.
I tried switching the related parts to double precision here, but I realized that would mean using double precision inside the node coordinates as well, which would have an impact on memory usage. Hopefully you will have a better idea at handling this, but you could use the index range check as a hotfix.