From 60ef74127512ab8134332432bceb6d5a932aee0c Mon Sep 17 00:00:00 2001 From: Bram Stolk Date: Tue, 23 Sep 2025 13:48:05 -0700 Subject: [PATCH 1/4] Add option to run unit tests with FP exceptions enabled. To catch FP exceptions, build as: $ cmake -D OPENVDB_TESTS_FPE=ON ... And to get callstacks in debugger, use: $ gdb --args ./openvdb/openvdb/unittest/vdb_test --gtest_catch_exceptions=0 This toggle will let you reproduce issues #2090 #2091 #2092 Signed-off-by: Bram Stolk --- openvdb/openvdb/unittest/CMakeLists.txt | 6 ++++++ openvdb/openvdb/unittest/main.cc | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/openvdb/openvdb/unittest/CMakeLists.txt b/openvdb/openvdb/unittest/CMakeLists.txt index 184e96a5d2..eed19b738c 100644 --- a/openvdb/openvdb/unittest/CMakeLists.txt +++ b/openvdb/openvdb/unittest/CMakeLists.txt @@ -18,6 +18,8 @@ set(OPENVDB_TESTS "" CACHE STRING [=[ \"Activate;NodeManager\" would build just the TestActivate.cc and TestNodeManager.cc unit tests.]=]) +option(OPENVDB_TESTS_FPE "Enable FP exceptions in unit tests (linux only)" FALSE) + ########################################################################## message(STATUS "----------------------------------------------------") @@ -196,6 +198,10 @@ else() ) endif() +if (OPENVDB_TESTS_FPE) + add_compile_definitions(OPENVDB_TESTS_FPE) +endif() + add_executable(vdb_test ${UNITTEST_SOURCE_FILES}) # Blosc and ZLib are hidden dependencies for the core library diff --git a/openvdb/openvdb/unittest/main.cc b/openvdb/openvdb/unittest/main.cc index 5066512862..63fac03ccd 100644 --- a/openvdb/openvdb/unittest/main.cc +++ b/openvdb/openvdb/unittest/main.cc @@ -12,11 +12,20 @@ #include #include +#if defined(__linux__) && defined(OPENVDB_TESTS_FPE) +#include +#endif + #include int main(int argc, char *argv[]) { ::testing::InitGoogleTest(&argc, argv); + +#if defined(__linux__) && defined(OPENVDB_TESTS_FPE) + feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); +#endif + return RUN_ALL_TESTS(); } From 495fda9f0ecb5af6fef46e9c0ebe9f22e5124b25 Mon Sep 17 00:00:00 2001 From: Bram Stolk Date: Tue, 23 Sep 2025 15:12:15 -0700 Subject: [PATCH 2/4] Fix division by zero causing FP exception during unit test run. FIXES #2091 Signed-off-by: Bram Stolk --- openvdb/openvdb/points/IndexFilter.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openvdb/openvdb/points/IndexFilter.h b/openvdb/openvdb/points/IndexFilter.h index 9f0e57d708..0c44126133 100644 --- a/openvdb/openvdb/points/IndexFilter.h +++ b/openvdb/openvdb/points/IndexFilter.h @@ -240,7 +240,8 @@ class RandomLeafFilter currentPoints += iter->pointCount(); } - const float factor = targetPoints > currentPoints ? 1.0f : float(targetPoints) / float(currentPoints); + const float denom = currentPoints > 0 ? float(currentPoints) : 1.0f; // Do not divide by zero. + const float factor = targetPoints > currentPoints ? 1.0f : float(targetPoints) / denom; std::mt19937 generator(seed); std::uniform_int_distribution dist(0, std::numeric_limits::max() - 1); From 51903084d6eff24bee12ed66551d9237c2246435 Mon Sep 17 00:00:00 2001 From: Bram Stolk Date: Wed, 24 Sep 2025 14:11:23 -0700 Subject: [PATCH 3/4] Do not take square root of negative values. FP exceptions were triggered in unit tests. FIXES #2092 Signed-off-by: Bram Stolk --- openvdb/openvdb/math/Stencils.h | 4 +++- openvdb/openvdb/tools/impl/ConvexVoxelizer.h | 20 ++++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/openvdb/openvdb/math/Stencils.h b/openvdb/openvdb/math/Stencils.h index 0c4ed2c0c8..5d145815d9 100644 --- a/openvdb/openvdb/math/Stencils.h +++ b/openvdb/openvdb/math/Stencils.h @@ -1627,7 +1627,9 @@ class CurvatureStencil: public BaseStencil, Grid Real alphaM, alphaG, normGrad; if (this->curvatures(alphaM, alphaG, normGrad)) { const Real mean = alphaM*mInv2Dx/math::Pow3(normGrad); - const Real tmp = std::sqrt(mean*mean - alphaG*mInvDx2/math::Pow4(normGrad)); + const Real base = mean*mean - alphaG*mInvDx2/math::Pow4(normGrad); + const Real clampVal = 0; + const Real tmp = std::sqrt(std::max(base, clampVal)); pair.first = ValueType(mean - tmp); pair.second = ValueType(mean + tmp); } diff --git a/openvdb/openvdb/tools/impl/ConvexVoxelizer.h b/openvdb/openvdb/tools/impl/ConvexVoxelizer.h index 5ce7226a7d..e00a09746d 100644 --- a/openvdb/openvdb/tools/impl/ConvexVoxelizer.h +++ b/openvdb/openvdb/tools/impl/ConvexVoxelizer.h @@ -389,7 +389,10 @@ class ConvexVoxelizer circleBottom(const ValueT& x0, const ValueT& y0, const ValueT& r, const ValueT& x) { - return y0 - math::Sqrt(math::Pow2(r) - math::Pow2(x-x0)); + const ValueT base = math::Pow2(r) - math::Pow2(x-x0); + return base <= 0 + ? y0 + : y0 - math::Sqrt(base); } /// @brief Computes the top y-coordinate of a circle at a given x position. @@ -402,7 +405,10 @@ class ConvexVoxelizer circleTop(const ValueT& x0, const ValueT& y0, const ValueT& r, const ValueT& x) { - return y0 + math::Sqrt(math::Pow2(r) - math::Pow2(x-x0)); + const ValueT base = math::Pow2(r) - math::Pow2(x-x0); + return base <= 0 + ? y0 + : y0 + math::Sqrt(base); } /// @brief Computes the bottom z-coordinate of a sphere at a given (x, y) position. @@ -417,7 +423,10 @@ class ConvexVoxelizer sphereBottom(const ValueT& x0, const ValueT& y0, const ValueT& z0, const ValueT& r, const ValueT& x, const ValueT& y) { - return z0 - math::Sqrt(math::Pow2(r) - math::Pow2(x-x0) - math::Pow2(y-y0)); + const ValueT base = math::Pow2(r) - math::Pow2(x-x0) - math::Pow2(y-y0); + return base <= 0 // Do not take square root of negative numbers. + ? z0 + : z0 - math::Sqrt(base); } /// @brief Computes the top z-coordinate of a sphere at a given (x, y) position. @@ -432,7 +441,10 @@ class ConvexVoxelizer sphereTop(const ValueT& x0, const ValueT& y0, const ValueT& z0, const ValueT& r, const ValueT& x, const ValueT& y) { - return z0 + math::Sqrt(math::Pow2(r) - math::Pow2(x-x0) - math::Pow2(y-y0)); + const ValueT base = math::Pow2(r) - math::Pow2(x-x0) - math::Pow2(y-y0); + return base <= 0 // Do not take square root of negative numbers. + ? z0 + : z0 + math::Sqrt(base); } // ------------ nested classes ------------ From bc381adca80719ce4432676903af238690ed1c61 Mon Sep 17 00:00:00 2001 From: Bram Stolk Date: Sun, 5 Oct 2025 19:24:02 -0700 Subject: [PATCH 4/4] Add env var for FE_OVERFLOW. Signed-off-by: Bram Stolk --- openvdb/openvdb/unittest/main.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/openvdb/openvdb/unittest/main.cc b/openvdb/openvdb/unittest/main.cc index 63fac03ccd..6faf197c9e 100644 --- a/openvdb/openvdb/unittest/main.cc +++ b/openvdb/openvdb/unittest/main.cc @@ -24,7 +24,12 @@ main(int argc, char *argv[]) ::testing::InitGoogleTest(&argc, argv); #if defined(__linux__) && defined(OPENVDB_TESTS_FPE) - feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); + int excepts = FE_DIVBYZERO | FE_INVALID; + if (getenv("OPENVDB_TEST_OVERFLOW")) { + // when set, test for FP overflow as well. + excepts = excepts | FE_OVERFLOW; + } + feenableexcept(excepts); #endif return RUN_ALL_TESTS();