From 6e1d15f8a2fb5baa808b24753dfc43da326bb305 Mon Sep 17 00:00:00 2001 From: S H <3655508+sh1boot@users.noreply.github.com> Date: Mon, 19 Oct 2026 18:44:24 -0700 Subject: [PATCH] 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. --- src/libslic3r/EdgeGrid.cpp | 2 +- tests/libslic3r/CMakeLists.txt | 1 + tests/libslic3r/test_edge_grid.cpp | 33 ++++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 tests/libslic3r/test_edge_grid.cpp diff --git a/src/libslic3r/EdgeGrid.cpp b/src/libslic3r/EdgeGrid.cpp index c6e003505a..35d3608dd8 100644 --- a/src/libslic3r/EdgeGrid.cpp +++ b/src/libslic3r/EdgeGrid.cpp @@ -616,7 +616,7 @@ struct PropagateDanielssonSingleStep { if ((signs[addr] & 2) == 0) { float *v = &L[addr << 1]; float l = v[0] * v[0] + v[1] * v[1]; - float *v2s = v + (addr_delta << 1); + float *v2s = v + 2 * addr_delta; float v2[2] = { v2s[0] + INCX * resolution, v2s[1] + INCY * resolution diff --git a/tests/libslic3r/CMakeLists.txt b/tests/libslic3r/CMakeLists.txt index 45b559af81..6ab08f797f 100644 --- a/tests/libslic3r/CMakeLists.txt +++ b/tests/libslic3r/CMakeLists.txt @@ -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 diff --git a/tests/libslic3r/test_edge_grid.cpp b/tests/libslic3r/test_edge_grid.cpp new file mode 100644 index 0000000000..406ea198cf --- /dev/null +++ b/tests/libslic3r/test_edge_grid.cpp @@ -0,0 +1,33 @@ +#include +#include +#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)); + } +}