Repository navigation
[filters] Reject voxel indices beyond int range in VoxelGridCovariance and VoxelGrid - #6492
Merged
mvieth merged 5 commits intoOct 22, 2026
Conversation
The existing check only limits the number of voxels. For a cloud far from the origin and a small leaf size, floor (coordinate * inverse leaf size) does not fit into an int. The cast is undefined behavior and distinct points end up in the same leaf. Warn and return like for a too large number of voxels.
VoxelGrid has the same check as VoxelGridCovariance, which only limits the number of voxels. For a cloud far from the origin and a small leaf size, floor (coordinate * inverse leaf size) does not fit into an int, the cast is undefined behavior and distinct points end up in the same leaf. Warn and return the input like for a too large number of voxels.
applyFilter returned before clearing the leaves when there was no input or the leaf size was too small for the input, so a reused filter kept the leaves of its previous input, and getLeaves, getLeaf and getNeighborhoodAtPoint answered from the old grid. Clear the leaves at the start of applyFilter, next to the leaf indices.
mvieth
reviewed
Oct 18, 2026
Comment on lines
+634
to
+635
| indices_fit = indices_fit && min_index >= -2147483648.0f && min_index < 2147483648.0f && | ||
| max_index >= -2147483648.0f && max_index < 2147483648.0f; |
Member
There was a problem hiding this comment.
Thanks for the PR! Is it possible to replace these "magic number" with some constant, probably static_cast<float>(std::numeric_limits<int>::lowest()) and static_cast<float>(std::numeric_limits<int>::max()), respectively? I think that would make the intent clearer.
Contributor
Author
Name the bounds of the int range instead of spelling out 2^31 as float literals; the values are unchanged.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #6174.
VoxelGridCovariance::applyFilteralready rejects input if the number of voxels would overflow an int, but it only looks at the extent(max_p - min_p) * inverse_leaf_size_. The indices of the first and last voxel,floor (min_p * inverse_leaf_size_)andfloor (max_p * inverse_leaf_size_), are then cast tointwithout a range check. For a cloud far from the origin and a small leaf size they do not fit, which is undefined behavior, and distinct points end up in the same leaf.Input from the issue: 10 points at
x = 1e7 + i, leaf size1e-3along x.getLeaves ().size ()is 1 instead of 10 (also what I get on arm64).VoxelGrid::applyFilterhas the same pattern and returns 1 point for that input, so it is fixed in a second commit.The fix checks, per axis and in float (the type of the expression that is cast), that both indices fit into an int. If not, it warns with the existing message and returns the same way as the existing check: empty output for
VoxelGridCovariance, the unfiltered input forVoxelGrid.I did not subtract
min_pbefore multiplying, as suggested in the issue. That moves the voxel boundaries from multiples of the leaf size tomin_p + k * leaf size, so different points would share a leaf and the NDT results of existing users would change. Rejecting also fits the public interface, which exposes the grid withintcoordinates (getMinBoxCoordinates,getGridCoordinates,getCentroidIndexAt). If a correct result for such clouds is preferred, that would be a separate change.Tests:
VoxelGridCovariance.VoxelIndicesBeyondIntRangeandVoxelGrid.VoxelIndicesBeyondIntRangeintest/filters/test_filters.cpp, along each axis. Offsets 0 and +-1e6 keep working, offsets +-1e7 and clouds where only the smallest or only the largest index is out of range are rejected. Without the fix the rejected cases fail (1 or 2 leaves or points instead of the expected result), with the fix the wholetest_filtersbinary passes.A third commit clears
leaves_at the start ofVoxelGridCovariance::applyFilter. Before, every early return (no input, the existing extent check, and now the index check) left the leaves of the previous input in place, so a reused filter answeredgetLeaves,getLeafandgetNeighborhoodAtPointfrom the old grid.VoxelGridCovariance.RejectedInputClearsLeavescovers that, andVoxelGrid.VoxelIndicesAtIntRangeBoundschecks the values at both ends of the int range (2^31 - 128 and -2^31 are accepted, 2^31 and -2^31 - 256 are rejected). I can move the third commit to its own PR if you prefer.VoxelGrid<PCLPointCloud2>(filters/src/voxel_grid.cpp),UniformSamplingandVoxelGridLabelhave the same unchecked cast and are not changed here.