Avoid signed-shift undefined behavior in EdgeGrid distance propagation (#16626)

Danielsson propagation in EdgeGrid::Grid::calculate_sdf() doubles a negative neighbor offset (-1 or -ncols) with a left shift, which is undefined behavior in C++17. Multiply by two instead.

Adds test_edge_grid.cpp, which checks signed distances inside and outside a rectangle beyond the initial edge band. Built with -fsanitize=shift, it aborts on the old code and passes with the fix.
This commit is contained in:
S H authored and GitHub committed 2026-10-19 20:44:24 -05:00
1 parent 4f63cd4051
commit 6e1d15f8a2
3 files changed
+35 -1

No files matched your search

+1
View File
@@ -35,6 +35,7 @@ add_executable(${_TEST_NAME}_tests
test_preset_diff.cpp
test_vendor_cache.cpp
test_preset_options.cpp
test_edge_grid.cpp
test_elephant_foot_compensation.cpp
test_fill_corner_smoothing.cpp
test_filament_mixer.cpp
+33
View File
@@ -0,0 +1,33 @@
#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_floating_point.hpp>
#include "catch2/matchers/catch_matchers.hpp"
#include "libslic3r/BoundingBox.hpp"
#include "libslic3r/EdgeGrid.hpp"
#include "libslic3r/Point.hpp"
#include "libslic3r/Polygon.hpp"
#include "libslic3r/libslic3r.h"
using namespace Slic3r;
TEST_CASE("EdgeGrid propagates signed distances across the interior and exterior", "[EdgeGrid][Regression]")
{
const Polygon rectangle {Point::new_scale(-10., -12.), Point::new_scale(10., -12.),
Point::new_scale(10., 12.), Point::new_scale(-10., 12.)};
const Polygons outlines {rectangle};
const BoundingBox bounds(Point::new_scale(-30., -32.), Point::new_scale(30., 32.));
EdgeGrid::Grid grid(bounds);
grid.create(outlines, scale_(1.));
// Distances beyond the initialized edge band require backward propagation.
// With -fsanitize=shift, this also checks negative neighbour offsets.
grid.calculate_sdf();
const auto distance = [&](double x, double y) {
return grid.signed_distance_bilinear(Point::new_scale(x, y)) * SCALING_FACTOR;
};
REQUIRE_THAT(distance(0., 0.), Catch::Matchers::WithinAbs(-10., 0.01));
for (double sign : {-1., 1.}) {
REQUIRE_THAT(distance(sign * 5., 0.), Catch::Matchers::WithinAbs(-5., 0.01));
REQUIRE_THAT(distance(0., sign * 7.), Catch::Matchers::WithinAbs(-5., 0.01));
REQUIRE_THAT(distance(sign * 20., 0.), Catch::Matchers::WithinAbs(10., 0.01));
REQUIRE_THAT(distance(0., sign * 22.), Catch::Matchers::WithinAbs(10., 0.01));
}
}