From 4aa66d20a595037eb2bc86c23682efc9bfc726ad Mon Sep 17 00:00:00 2001 From: Gopalakrishnan Nallasamy Date: Thu, 23 Apr 2026 16:11:36 -0700 Subject: [PATCH 1/6] GridSample: guard reflection-padding index math against extreme coordinates Extreme grid coordinates could produce out-of-range indices in the reflection branch of PixelAtGrid. Two minimal changes: 1. In GsReflect, widen the int n = static_cast(dx / range) computation to int64_t. For large (but finite) inputs, dx / range can exceed INT_MAX, making the narrow int cast undefined behavior. 2. In PixelAtGrid / PixelAtGrid3D, clamp the int64_t index returned by GsReflect back into [0, W-1] / [0, H-1] / [0, D-1] before indexing the image buffer, guaranteeing the final load stays in bounds. Adds a regression test covering reflection padding with large-magnitude grid coordinates. --- .../core/providers/cpu/tensor/grid_sample.cc | 17 ++++++++-- .../cpu/tensor/grid_sample_test_custom.inc | 34 +++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/onnxruntime/core/providers/cpu/tensor/grid_sample.cc b/onnxruntime/core/providers/cpu/tensor/grid_sample.cc index df0bc235a4f9e..f08c144c608f5 100644 --- a/onnxruntime/core/providers/cpu/tensor/grid_sample.cc +++ b/onnxruntime/core/providers/cpu/tensor/grid_sample.cc @@ -65,7 +65,9 @@ T GsReflect(T x, T x_min, T x_max) { T range = x_max - x_min; if (fx < x_min) { dx = x_min - fx; - int n = static_cast(dx / range); + // Use int64_t rather than int: for extreme (but finite) inputs, dx / range can exceed + // INT_MAX, making a float->int cast undefined behavior. + int64_t n = static_cast(dx / range); T r = dx - n * range; if (n % 2 == 0) { fx = x_min + r; @@ -74,7 +76,7 @@ T GsReflect(T x, T x_min, T x_max) { } } else if (fx > x_max) { dx = fx - x_max; - int n = static_cast(dx / range); + int64_t n = static_cast(dx / range); T r = dx - n * range; if (n % 2 == 0) { fx = x_max - r; @@ -124,6 +126,11 @@ T GridSample::PixelAtGrid(const T* image, int64_t r, int64_t c, int64_t H, in } else { // (padding_mode_ == Reflection) c = static_cast(GsReflect(static_cast(c), border[0], border[2])); r = static_cast(GsReflect(static_cast(r), border[1], border[3])); + // Safety clamp: GsReflect is computed in floating point and casts back to int64_t. + // Extreme grid coordinates can overflow that cast, so clamp the resulting indices + // back into the image range before indexing. + c = std::clamp(c, 0, W - 1); + r = std::clamp(r, 0, H - 1); pixel = image[r * W + c]; } return pixel; @@ -145,6 +152,12 @@ T GridSample::PixelAtGrid3D(const T* image, int64_t d, int64_t h, int64_t w, w = static_cast(GsReflect(static_cast(w), border[0], border[3])); h = static_cast(GsReflect(static_cast(h), border[1], border[4])); d = static_cast(GsReflect(static_cast(d), border[2], border[5])); + // Safety clamp: GsReflect is computed in floating point and casts back to int64_t. + // Extreme grid coordinates can overflow that cast, so clamp the resulting indices + // back into the image range before indexing. + w = std::clamp(w, 0, W - 1); + h = std::clamp(h, 0, H - 1); + d = std::clamp(d, 0, D - 1); pixel = image[d * H * W + h * W + w]; } return pixel; diff --git a/onnxruntime/test/providers/cpu/tensor/grid_sample_test_custom.inc b/onnxruntime/test/providers/cpu/tensor/grid_sample_test_custom.inc index 2423d7f120b20..9e120691750d4 100644 --- a/onnxruntime/test/providers/cpu/tensor/grid_sample_test_custom.inc +++ b/onnxruntime/test/providers/cpu/tensor/grid_sample_test_custom.inc @@ -71,3 +71,37 @@ TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_linear_zeros_mixed_bound test.AddOutput("Y", Y_shape, Y_data); RunTests(test, GetExecutionProviders()); } + +TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_nearest_reflection_extreme_coords) { + // Regression test: large grid coordinates previously produced wild indices in the + // reflection branch of PixelAtGrid. The internal division-and-int-cast inside + // GsReflect now uses int64_t, and PixelAtGrid clamps the resulting index back into + // the image range, so sampling stays in bounds. Using "nearest" mode keeps the test + // focused on the reflection index path (no bilinear weight arithmetic), and using a + // constant-valued input makes the expected output deterministic regardless of which + // in-range pixel is hit. + OpTester test("GridSample", 20); + test.AddAttribute("mode", std::string("nearest")); + test.AddAttribute("padding_mode", std::string("reflection")); + test.AddAttribute("align_corners", int64_t{0}); + + std::initializer_list X_shape{1, 1, 2, 2}; + std::initializer_list X_data{TypeParam(1.0f), TypeParam(1.0f), + TypeParam(1.0f), TypeParam(1.0f)}; + + std::initializer_list Grid_shape{1, 1, 2, 2}; + // 1e+10 exceeds INT_MAX, so the pre-fix `int n = static_cast(dx / range)` + // inside GsReflect would invoke undefined behavior; 1e+10 still fits comfortably + // in int64_t. For MLFloat16 the value overflows to +/-Inf, exercising the same + // safety-clamp fallback in PixelAtGrid. + std::initializer_list Grid_data{ + TypeParam(1.0e+10f), TypeParam(1.0e+10f), + TypeParam(-1.0e+10f), TypeParam(-1.0e+10f)}; + + std::initializer_list Y_shape{1, 1, 1, 2}; + + test.AddInput("X", X_shape, X_data); + test.AddInput("Grid", Grid_shape, Grid_data); + test.AddOutput("Y", Y_shape, {TypeParam(1.0f), TypeParam(1.0f)}); + RunTests(test, GetExecutionProviders()); +} From 5e59984aa8d04bca94226160f16dd33a8474df00 Mon Sep 17 00:00:00 2001 From: Gopalakrishnan Nallasamy Date: Thu, 30 Apr 2026 13:21:39 -0700 Subject: [PATCH 2/6] Address review: harden GsReflect and float->int64 casts in GridSample CPU Addresses yuslepukhin's review comments on PR #27975: - GsReflect: add explicit guard for non-finite input or non-positive range (returns x_min) before the existing reduction logic so the int64 cast inside GsReflect is never invoked on NaN/Inf or with range == 0. - Introduce IsSafeForInt64Conversion() helper and sanitize unsafe coordinates to the in-range border value (x_min/y_min/z_min) before the float->int64 conversions in: * GridSample::Compute 2D loop (Nearest/Linear/Cubic), * GridSample::Compute 3D loop, * PrecomputeBilinearSamplePlan2D fast path (substitutes -0.5 so the mask logic continues to reject the out-of-range neighbors). This eliminates undefined behavior from static_cast on values outside [INT64_MIN, INT64_MAX] or NaN/Inf. - Add and includes. - Expand custom tests to cover NaN, +/-Inf, extreme finite coords across bilinear/cubic + reflection, 3D nearest + reflection, bilinear + border, and dim=1 with align_corners=1 (range == 0 in GsReflect). --- .../core/providers/cpu/tensor/grid_sample.cc | 56 +++++- .../cpu/tensor/grid_sample_test_custom.inc | 189 ++++++++++++++++++ 2 files changed, 243 insertions(+), 2 deletions(-) diff --git a/onnxruntime/core/providers/cpu/tensor/grid_sample.cc b/onnxruntime/core/providers/cpu/tensor/grid_sample.cc index f08c144c608f5..34135ca62e4a8 100644 --- a/onnxruntime/core/providers/cpu/tensor/grid_sample.cc +++ b/onnxruntime/core/providers/cpu/tensor/grid_sample.cc @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. +#include +#include #include #include "core/common/safeint.h" @@ -63,6 +65,11 @@ T GsReflect(T x, T x_min, T x_max) { T dx = {}; T fx = static_cast(x); T range = x_max - x_min; + // Guard against NaN, Inf, or non-positive range (e.g. dim==1 with align_corners=true) + // which would otherwise produce wild indices via division by zero or UB float->int casts. + if (!std::isfinite(fx) || !(range > T{0})) { + return x_min; + } if (fx < x_min) { dx = x_min - fx; // Use int64_t rather than int: for extreme (but finite) inputs, dx / range can exceed @@ -88,6 +95,15 @@ T GsReflect(T x, T x_min, T x_max) { return static_cast(fx); } +// Returns true when v is finite and its magnitude is small enough that converting it to +// int64_t via std::floor / std::nearbyint is well-defined. 2^62 is far below INT64_MAX +// (~9.22e18) and leaves ample margin for any realistic image dimension. +template +inline bool IsSafeForInt64Conversion(T v) { + constexpr T kSafeBound = static_cast(int64_t{1} << 62); + return std::isfinite(v) && v >= -kSafeBound && v <= kSafeBound; +} + // Calculate cubic convolution interpolation coefficients // ROBERT G. KEYS https://ieeexplore.ieee.org/document/1163711 template @@ -199,8 +215,19 @@ void PrecomputeBilinearSamplePlan2D(const T* grid_data, auto& plan = plans[idx]; const T nx = grid_data[idx * 2]; const T ny = grid_data[idx * 2 + 1]; - const T x = GsDenormalize(nx, W_in, false); - const T y = GsDenormalize(ny, H_in, false); + T x = GsDenormalize(nx, W_in, false); + T y = GsDenormalize(ny, H_in, false); + + // Sanitize coordinates that are non-finite or whose magnitude is too large + // for a safe float->int64 conversion via std::floor. The fast path is only used + // for zeros padding without align_corners, so substituting the lower border (-0.5) + // produces an out-of-bounds floor index that the mask logic correctly rejects. + if (!IsSafeForInt64Conversion(x)) { + x = static_cast(-0.5f); + } + if (!IsSafeForInt64Conversion(y)) { + y = static_cast(-0.5f); + } const int64_t x1 = static_cast(std::floor(x)); const int64_t y1 = static_cast(std::floor(y)); @@ -411,6 +438,17 @@ Status GridSample::Compute(OpKernelContext* context) const { auto x = GsDenormalize(nx, W_in, align_corners_); // actual location auto y = GsDenormalize(ny, H_in, align_corners_); + // Sanitize coordinates that are non-finite or whose magnitude is too large + // for a safe float->int64 conversion via std::floor / std::nearbyint. + // Substituting the in-range border value keeps the subsequent casts + // well-defined while still producing a defined output for each padding mode. + if (!IsSafeForInt64Conversion(x)) { + x = x_min; + } + if (!IsSafeForInt64Conversion(y)) { + y = y_min; + } + if (mode_ == Nearest) { x = static_cast(std::nearbyint(static_cast(x))); y = static_cast(std::nearbyint(static_cast(y))); @@ -509,6 +547,20 @@ Status GridSample::Compute(OpKernelContext* context) const { auto y = GsDenormalize(ny, H_in, align_corners_); auto z = GsDenormalize(nz, D_in, align_corners_); + // Sanitize coordinates that are non-finite or whose magnitude is too large + // for a safe float->int64 conversion via std::floor / std::nearbyint. + // Substituting the in-range border value keeps the subsequent casts + // well-defined while still producing a defined output for each padding mode. + if (!IsSafeForInt64Conversion(x)) { + x = x_min; + } + if (!IsSafeForInt64Conversion(y)) { + y = y_min; + } + if (!IsSafeForInt64Conversion(z)) { + z = z_min; + } + if (mode_ == Nearest) { x = static_cast(std::nearbyint(static_cast(x))); y = static_cast(std::nearbyint(static_cast(y))); diff --git a/onnxruntime/test/providers/cpu/tensor/grid_sample_test_custom.inc b/onnxruntime/test/providers/cpu/tensor/grid_sample_test_custom.inc index 9e120691750d4..7c95174c565b8 100644 --- a/onnxruntime/test/providers/cpu/tensor/grid_sample_test_custom.inc +++ b/onnxruntime/test/providers/cpu/tensor/grid_sample_test_custom.inc @@ -105,3 +105,192 @@ TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_nearest_reflection_extre test.AddOutput("Y", Y_shape, {TypeParam(1.0f), TypeParam(1.0f)}); RunTests(test, GetExecutionProviders()); } + +TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_nearest_reflection_nan_coords) { + // Regression test: NaN grid coordinates would otherwise propagate into + // static_cast(std::nearbyint(NaN)), which is undefined behavior. + // The Compute loop now sanitizes such coordinates to the in-range border + // before performing the cast, producing defined sampling. + OpTester test("GridSample", 20); + test.AddAttribute("mode", std::string("nearest")); + test.AddAttribute("padding_mode", std::string("reflection")); + test.AddAttribute("align_corners", int64_t{0}); + + std::initializer_list X_shape{1, 1, 2, 2}; + std::initializer_list X_data{TypeParam(1.0f), TypeParam(1.0f), + TypeParam(1.0f), TypeParam(1.0f)}; + + std::initializer_list Grid_shape{1, 1, 2, 2}; + const float nan_val = std::numeric_limits::quiet_NaN(); + std::initializer_list Grid_data{ + TypeParam(nan_val), TypeParam(nan_val), + TypeParam(0.0f), TypeParam(nan_val)}; + + std::initializer_list Y_shape{1, 1, 1, 2}; + + test.AddInput("X", X_shape, X_data); + test.AddInput("Grid", Grid_shape, Grid_data); + // With a constant-valued image any reflected pixel returns 1.0. + test.AddOutput("Y", Y_shape, {TypeParam(1.0f), TypeParam(1.0f)}); + RunTests(test, GetExecutionProviders()); +} + +TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_bilinear_reflection_infinity_coords) { + // Regression test: Inf grid coordinates would otherwise reach + // static_cast(std::floor(Inf)), which is undefined behavior. + OpTester test("GridSample", 20); + test.AddAttribute("mode", std::string("linear")); + test.AddAttribute("padding_mode", std::string("reflection")); + test.AddAttribute("align_corners", int64_t{0}); + + std::initializer_list X_shape{1, 1, 2, 2}; + std::initializer_list X_data{TypeParam(1.0f), TypeParam(1.0f), + TypeParam(1.0f), TypeParam(1.0f)}; + + std::initializer_list Grid_shape{1, 1, 2, 2}; + const float inf_val = std::numeric_limits::infinity(); + std::initializer_list Grid_data{ + TypeParam(inf_val), TypeParam(-inf_val), + TypeParam(-inf_val), TypeParam(inf_val)}; + + std::initializer_list Y_shape{1, 1, 1, 2}; + + test.AddInput("X", X_shape, X_data); + test.AddInput("Grid", Grid_shape, Grid_data); + // Constant-valued image: any reflected sample returns 1.0. + test.AddOutput("Y", Y_shape, {TypeParam(1.0f), TypeParam(1.0f)}); + RunTests(test, GetExecutionProviders()); +} + +TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_bilinear_reflection_extreme_coords) { + // Bilinear interpolation path: the four corner indices are computed via + // static_cast(std::floor(x)). With a constant-valued image the + // expected output is 1.0 regardless of which reflected pixel is hit. + OpTester test("GridSample", 20); + test.AddAttribute("mode", std::string("linear")); + test.AddAttribute("padding_mode", std::string("reflection")); + test.AddAttribute("align_corners", int64_t{0}); + + std::initializer_list X_shape{1, 1, 2, 2}; + std::initializer_list X_data{TypeParam(1.0f), TypeParam(1.0f), + TypeParam(1.0f), TypeParam(1.0f)}; + + std::initializer_list Grid_shape{1, 1, 2, 2}; + std::initializer_list Grid_data{ + TypeParam(1.0e+20f), TypeParam(1.0e+20f), + TypeParam(-1.0e+20f), TypeParam(-1.0e+20f)}; + + std::initializer_list Y_shape{1, 1, 1, 2}; + + test.AddInput("X", X_shape, X_data); + test.AddInput("Grid", Grid_shape, Grid_data); + // With a constant-valued image any sampled pixel is 1.0. + test.AddOutput("Y", Y_shape, {TypeParam(1.0f), TypeParam(1.0f)}); + RunTests(test, GetExecutionProviders()); +} + +TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_cubic_reflection_extreme_coords) { + // Cubic interpolation path: the 4x4 neighborhood is computed via + // static_cast(std::floor(x)) - 1, exercising the same UB-prone cast. + // Cubic only supports float (T1 type constraint), so this test is float-only. + OpTester test("GridSample", 20); + test.AddAttribute("mode", std::string("cubic")); + test.AddAttribute("padding_mode", std::string("reflection")); + test.AddAttribute("align_corners", int64_t{0}); + + std::initializer_list X_shape{1, 1, 4, 4}; + std::initializer_list X_data{ + TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f), + TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f), + TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f), + TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f)}; + + std::initializer_list Grid_shape{1, 1, 1, 2}; + std::initializer_list Grid_data{ + TypeParam(1.0e+10f), TypeParam(-1.0e+10f)}; + + std::initializer_list Y_shape{1, 1, 1, 1}; + + test.AddInput("X", X_shape, X_data); + test.AddInput("Grid", Grid_shape, Grid_data); + // Constant-valued image: cubic interpolation of all-1.0 neighborhood is 1.0. + test.AddOutput("Y", Y_shape, {TypeParam(1.0f)}); + RunTests(test, GetExecutionProviders()); +} + +TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_5D_nearest_reflection_extreme_coords) { + // 3D / 5-D input: the reflection branch in PixelAtGrid3D received the same + // safety clamp as PixelAtGrid; this test exercises that path. + OpTester test("GridSample", 20); + test.AddAttribute("mode", std::string("nearest")); + test.AddAttribute("padding_mode", std::string("reflection")); + test.AddAttribute("align_corners", int64_t{0}); + + std::initializer_list X_shape{1, 1, 2, 2, 2}; + std::initializer_list X_data{ + TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f), + TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f)}; + + std::initializer_list Grid_shape{1, 1, 1, 2, 3}; + std::initializer_list Grid_data{ + TypeParam(1.0e+10f), TypeParam(1.0e+10f), TypeParam(1.0e+10f), + TypeParam(-1.0e+10f), TypeParam(-1.0e+10f), TypeParam(-1.0e+10f)}; + + std::initializer_list Y_shape{1, 1, 1, 1, 2}; + + test.AddInput("X", X_shape, X_data); + test.AddInput("Grid", Grid_shape, Grid_data); + test.AddOutput("Y", Y_shape, {TypeParam(1.0f), TypeParam(1.0f)}); + RunTests(test, GetExecutionProviders()); +} + +TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_nearest_reflection_dim1_align_corners) { + // With a 1x1 image and align_corners=true, x_min == x_max so the reflection + // range is zero. GsReflect must not divide by zero on any out-of-range coord. + OpTester test("GridSample", 20); + test.AddAttribute("mode", std::string("nearest")); + test.AddAttribute("padding_mode", std::string("reflection")); + test.AddAttribute("align_corners", int64_t{1}); + + std::initializer_list X_shape{1, 1, 1, 1}; + std::initializer_list X_data{TypeParam(7.0f)}; + + std::initializer_list Grid_shape{1, 1, 2, 2}; + std::initializer_list Grid_data{ + TypeParam(0.5f), TypeParam(0.5f), + TypeParam(-0.5f), TypeParam(-0.5f)}; + + std::initializer_list Y_shape{1, 1, 1, 2}; + + test.AddInput("X", X_shape, X_data); + test.AddInput("Grid", Grid_shape, Grid_data); + // The single input pixel is the only valid sample for any reflected coordinate. + test.AddOutput("Y", Y_shape, {TypeParam(7.0f), TypeParam(7.0f)}); + RunTests(test, GetExecutionProviders()); +} + +TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_bilinear_border_extreme_coords) { + // Border padding mode is independently safe via std::clamp; this regression + // test ensures it stays safe with extreme grid coordinates. + OpTester test("GridSample", 20); + test.AddAttribute("mode", std::string("linear")); + test.AddAttribute("padding_mode", std::string("border")); + test.AddAttribute("align_corners", int64_t{0}); + + std::initializer_list X_shape{1, 1, 2, 2}; + std::initializer_list X_data{TypeParam(1.0f), TypeParam(1.0f), + TypeParam(1.0f), TypeParam(1.0f)}; + + std::initializer_list Grid_shape{1, 1, 2, 2}; + std::initializer_list Grid_data{ + TypeParam(1.0e+20f), TypeParam(1.0e+20f), + TypeParam(-1.0e+20f), TypeParam(-1.0e+20f)}; + + std::initializer_list Y_shape{1, 1, 1, 2}; + + test.AddInput("X", X_shape, X_data); + test.AddInput("Grid", Grid_shape, Grid_data); + // Constant-valued image: any clamped border sample is 1.0. + test.AddOutput("Y", Y_shape, {TypeParam(1.0f), TypeParam(1.0f)}); + RunTests(test, GetExecutionProviders()); +} From bcca1e8e4f0de7289f2da3fd2e8e625b797886a6 Mon Sep 17 00:00:00 2001 From: Gopalakrishnan Nallasamy Date: Thu, 30 Apr 2026 14:39:32 -0700 Subject: [PATCH 3/6] Rename grid_sample_test_custom.inc to .cc with copyright header Promote the custom GridSample tests from a header-style .inc included into grid_sample_test.cc to a standalone translation unit: - Add MIT copyright header, includes, and namespace wrapping. - Move GetExecutionProviders/RunTests helpers into an anonymous namespace inside the new file (separate internal-linkage copies, so there is no ODR conflict with the versions in grid_sample_test.cc). - Remove the #include from grid_sample_test.cc. - Add the new file to the Emscripten exclusion list in cmake/onnxruntime_unittests.cmake alongside grid_sample_test.cc. --- cmake/onnxruntime_unittests.cmake | 3 +- .../providers/cpu/tensor/grid_sample_test.cc | 4 +- ..._custom.inc => grid_sample_test_custom.cc} | 58 ++++++++++++++++++- 3 files changed, 61 insertions(+), 4 deletions(-) rename onnxruntime/test/providers/cpu/tensor/{grid_sample_test_custom.inc => grid_sample_test_custom.cc} (89%) diff --git a/cmake/onnxruntime_unittests.cmake b/cmake/onnxruntime_unittests.cmake index bd12b50b7af43..7f361aa63921f 100644 --- a/cmake/onnxruntime_unittests.cmake +++ b/cmake/onnxruntime_unittests.cmake @@ -1025,7 +1025,8 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") endif() list(REMOVE_ITEM all_tests "${TEST_SRC_DIR}/providers/cpu/reduction/reduction_ops_test.cc" - "${TEST_SRC_DIR}/providers/cpu/tensor/grid_sample_test.cc") + "${TEST_SRC_DIR}/providers/cpu/tensor/grid_sample_test.cc" + "${TEST_SRC_DIR}/providers/cpu/tensor/grid_sample_test_custom.cc") endif() if (CMAKE_SYSTEM_NAME STREQUAL "Emscripten" OR IOS) diff --git a/onnxruntime/test/providers/cpu/tensor/grid_sample_test.cc b/onnxruntime/test/providers/cpu/tensor/grid_sample_test.cc index f10aa5a49c120..4dc3aa9b652a7 100755 --- a/onnxruntime/test/providers/cpu/tensor/grid_sample_test.cc +++ b/onnxruntime/test/providers/cpu/tensor/grid_sample_test.cc @@ -38,8 +38,8 @@ void RunTests(T& test, std::vector>&& execut execution_providers.clear(); } -// Custom tests not generated by grid_sample_test_gen.py. -#include "test/providers/cpu/tensor/grid_sample_test_custom.inc" +// Custom tests not generated by grid_sample_test_gen.py live in +// grid_sample_test_custom.cc. // DO NOT edit following tests. They are generated by: // onnxruntime/test/providers/cpu/tensor/grid_sample_test_gen.py diff --git a/onnxruntime/test/providers/cpu/tensor/grid_sample_test_custom.inc b/onnxruntime/test/providers/cpu/tensor/grid_sample_test_custom.cc similarity index 89% rename from onnxruntime/test/providers/cpu/tensor/grid_sample_test_custom.inc rename to onnxruntime/test/providers/cpu/tensor/grid_sample_test_custom.cc index 7c95174c565b8..205d2ddb571dc 100644 --- a/onnxruntime/test/providers/cpu/tensor/grid_sample_test_custom.inc +++ b/onnxruntime/test/providers/cpu/tensor/grid_sample_test_custom.cc @@ -1,5 +1,58 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. -// Custom tests are kept in a separate include to avoid regenerating the main file. +// Custom GridSample tests not generated by grid_sample_test_gen.py. +// These cover edge cases (extreme coordinates, NaN/Inf, dim==1, border, 3D) +// that exercise the float->int64 cast hardening in +// onnxruntime/core/providers/cpu/tensor/grid_sample.cc. + +#include +#include +#include +#include + +#include "gtest/gtest.h" + +#include "core/framework/execution_provider.h" +#include "test/providers/provider_test_utils.h" +#include "test/util/include/default_providers.h" + +namespace onnxruntime { +namespace test { +namespace { + +std::vector> GetExecutionProviders() { + std::vector> execution_providers; + + execution_providers.emplace_back(DefaultCpuExecutionProvider()); + +#ifdef USE_CUDA + execution_providers.emplace_back(DefaultCudaExecutionProvider()); +#ifdef ENABLE_CUDA_NHWC_OPS + execution_providers.push_back(DefaultCudaNHWCExecutionProvider()); +#endif +#endif + +#if defined(USE_COREML) + execution_providers.push_back(DefaultCoreMLExecutionProvider(/*use_mlprogram*/ true)); +#endif + +#ifdef USE_WEBGPU + execution_providers.push_back(DefaultWebGpuExecutionProvider()); +#endif + + return execution_providers; +} + +template +void RunTests(T& test, std::vector>&& execution_providers) { + for (size_t idx = 0; idx < execution_providers.size(); ++idx) { + test.ConfigEp(std::move(execution_providers[idx])).RunWithConfig(); + } + execution_providers.clear(); +} + +} // namespace template class GridSampleCustomTest : public ::testing::Test { @@ -294,3 +347,6 @@ TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_bilinear_border_extreme_ test.AddOutput("Y", Y_shape, {TypeParam(1.0f), TypeParam(1.0f)}); RunTests(test, GetExecutionProviders()); } + +} // namespace test +} // namespace onnxruntime From 182390b3f5f8f154e33ecfd5e961bade4d1d41b7 Mon Sep 17 00:00:00 2001 From: Gopalakrishnan Nallasamy Date: Thu, 30 Apr 2026 19:24:29 -0700 Subject: [PATCH 4/6] Scope GridSample pathological tests to CPU EP; cubic test float-only The pathological-coordinate regression tests (NaN/Inf/extreme grid values) target CPU-side hardening. Running them against non-CPU EPs (CUDA/CoreML/iOS/WebGPU) introduces unrelated backend behavior and broad provider-test failure cascades. Restrict those tests to the CPU EP via a new RunCpuOnly helper. The cubic test is also converted to a non-typed TEST over float only, since ONNX GridSample cubic mode constrains T1 to float (the MLFloat16 instantiation was a no-op). The two boundary-condition tests (linear_zeros_mixed_bounds_*) continue to run on all available EPs as cross-EP correctness checks. --- .../cpu/tensor/grid_sample_test_custom.cc | 48 +++++++++++-------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/onnxruntime/test/providers/cpu/tensor/grid_sample_test_custom.cc b/onnxruntime/test/providers/cpu/tensor/grid_sample_test_custom.cc index 205d2ddb571dc..f556bc10073c1 100644 --- a/onnxruntime/test/providers/cpu/tensor/grid_sample_test_custom.cc +++ b/onnxruntime/test/providers/cpu/tensor/grid_sample_test_custom.cc @@ -21,6 +21,12 @@ namespace onnxruntime { namespace test { namespace { +std::vector> GetCpuExecutionProviders() { + std::vector> execution_providers; + execution_providers.emplace_back(DefaultCpuExecutionProvider()); + return execution_providers; +} + std::vector> GetExecutionProviders() { std::vector> execution_providers; @@ -52,6 +58,11 @@ void RunTests(T& test, std::vector>&& execut execution_providers.clear(); } +template +void RunCpuOnly(T& test) { + RunTests(test, GetCpuExecutionProviders()); +} + } // namespace template @@ -156,7 +167,7 @@ TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_nearest_reflection_extre test.AddInput("X", X_shape, X_data); test.AddInput("Grid", Grid_shape, Grid_data); test.AddOutput("Y", Y_shape, {TypeParam(1.0f), TypeParam(1.0f)}); - RunTests(test, GetExecutionProviders()); + RunCpuOnly(test); } TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_nearest_reflection_nan_coords) { @@ -185,7 +196,7 @@ TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_nearest_reflection_nan_c test.AddInput("Grid", Grid_shape, Grid_data); // With a constant-valued image any reflected pixel returns 1.0. test.AddOutput("Y", Y_shape, {TypeParam(1.0f), TypeParam(1.0f)}); - RunTests(test, GetExecutionProviders()); + RunCpuOnly(test); } TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_bilinear_reflection_infinity_coords) { @@ -212,7 +223,7 @@ TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_bilinear_reflection_infi test.AddInput("Grid", Grid_shape, Grid_data); // Constant-valued image: any reflected sample returns 1.0. test.AddOutput("Y", Y_shape, {TypeParam(1.0f), TypeParam(1.0f)}); - RunTests(test, GetExecutionProviders()); + RunCpuOnly(test); } TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_bilinear_reflection_extreme_coords) { @@ -239,10 +250,10 @@ TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_bilinear_reflection_extr test.AddInput("Grid", Grid_shape, Grid_data); // With a constant-valued image any sampled pixel is 1.0. test.AddOutput("Y", Y_shape, {TypeParam(1.0f), TypeParam(1.0f)}); - RunTests(test, GetExecutionProviders()); + RunCpuOnly(test); } -TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_cubic_reflection_extreme_coords) { +TEST(GridSampleCustomTestFloatOnly, test_grid_sample_20_4D_cubic_reflection_extreme_coords) { // Cubic interpolation path: the 4x4 neighborhood is computed via // static_cast(std::floor(x)) - 1, exercising the same UB-prone cast. // Cubic only supports float (T1 type constraint), so this test is float-only. @@ -252,23 +263,22 @@ TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_cubic_reflection_extreme test.AddAttribute("align_corners", int64_t{0}); std::initializer_list X_shape{1, 1, 4, 4}; - std::initializer_list X_data{ - TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f), - TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f), - TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f), - TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f)}; + std::initializer_list X_data{ + 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f}; std::initializer_list Grid_shape{1, 1, 1, 2}; - std::initializer_list Grid_data{ - TypeParam(1.0e+10f), TypeParam(-1.0e+10f)}; + std::initializer_list Grid_data{1.0e+10f, -1.0e+10f}; std::initializer_list Y_shape{1, 1, 1, 1}; - test.AddInput("X", X_shape, X_data); - test.AddInput("Grid", Grid_shape, Grid_data); + test.AddInput("X", X_shape, X_data); + test.AddInput("Grid", Grid_shape, Grid_data); // Constant-valued image: cubic interpolation of all-1.0 neighborhood is 1.0. - test.AddOutput("Y", Y_shape, {TypeParam(1.0f)}); - RunTests(test, GetExecutionProviders()); + test.AddOutput("Y", Y_shape, {1.0f}); + RunCpuOnly(test); } TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_5D_nearest_reflection_extreme_coords) { @@ -294,7 +304,7 @@ TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_5D_nearest_reflection_extre test.AddInput("X", X_shape, X_data); test.AddInput("Grid", Grid_shape, Grid_data); test.AddOutput("Y", Y_shape, {TypeParam(1.0f), TypeParam(1.0f)}); - RunTests(test, GetExecutionProviders()); + RunCpuOnly(test); } TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_nearest_reflection_dim1_align_corners) { @@ -319,7 +329,7 @@ TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_nearest_reflection_dim1_ test.AddInput("Grid", Grid_shape, Grid_data); // The single input pixel is the only valid sample for any reflected coordinate. test.AddOutput("Y", Y_shape, {TypeParam(7.0f), TypeParam(7.0f)}); - RunTests(test, GetExecutionProviders()); + RunCpuOnly(test); } TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_bilinear_border_extreme_coords) { @@ -345,7 +355,7 @@ TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_bilinear_border_extreme_ test.AddInput("Grid", Grid_shape, Grid_data); // Constant-valued image: any clamped border sample is 1.0. test.AddOutput("Y", Y_shape, {TypeParam(1.0f), TypeParam(1.0f)}); - RunTests(test, GetExecutionProviders()); + RunCpuOnly(test); } } // namespace test From ce2d84237f8ff3ab6df14d1c9fe3427866d1b8bf Mon Sep 17 00:00:00 2001 From: Gopalakrishnan Nallasamy Date: Fri, 1 May 2026 12:51:33 -0700 Subject: [PATCH 5/6] GridSample: expand pathological-coordinate test coverage Add 7 new CPU-only regression tests for the float->int64 cast hardening: - linear+zeros+extreme/NaN/Inf: confirms IsSafeForInt64Conversion does not break the bilinear zeros-padding fast path. - cubic+NaN/Inf: covers NaN/+Inf/-Inf paths through the cubic kernel (float-only). - 5D linear+extreme: 3D trilinear path with extreme finite coordinates. - 5D nearest+NaN/Inf: 3D path with non-finite values along different axes. - align_corners=1 non-degenerate (3x3) image with extreme/NaN coords: verifies sanitization to x_min=0 maps to pixel(0,0). - negative-only extreme on non-constant image: verifies sanitization is direction-agnostic and rounds to pixel(0,0). - mixed normal+pathological grid in one call on a non-constant image: verifies normal points sample correctly and only unsafe coords are sanitized. --- .../cpu/tensor/grid_sample_test_custom.cc | 220 ++++++++++++++++++ 1 file changed, 220 insertions(+) diff --git a/onnxruntime/test/providers/cpu/tensor/grid_sample_test_custom.cc b/onnxruntime/test/providers/cpu/tensor/grid_sample_test_custom.cc index f556bc10073c1..16b622359c150 100644 --- a/onnxruntime/test/providers/cpu/tensor/grid_sample_test_custom.cc +++ b/onnxruntime/test/providers/cpu/tensor/grid_sample_test_custom.cc @@ -358,5 +358,225 @@ TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_bilinear_border_extreme_ RunCpuOnly(test); } +TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_linear_zeros_extreme_nan_inf_coords) { + // Zeros padding is safe by design, but the IsSafeForInt64Conversion sanitization + // (in PrecomputeBilinearSamplePlan2D) replaces NaN/Inf/extreme values with the + // lower border (-0.5) before the floor cast. Verify the optimized bilinear + // zeros-padding fast path still produces a deterministic, well-defined output + // for those inputs. + OpTester test("GridSample", 20); + test.AddAttribute("mode", std::string("linear")); + test.AddAttribute("padding_mode", std::string("zeros")); + test.AddAttribute("align_corners", int64_t{0}); + + std::initializer_list X_shape{1, 1, 2, 2}; + std::initializer_list X_data{TypeParam(1.0f), TypeParam(1.0f), + TypeParam(1.0f), TypeParam(1.0f)}; + + std::initializer_list Grid_shape{1, 1, 3, 2}; + std::initializer_list Grid_data{ + TypeParam(std::numeric_limits::quiet_NaN()), + TypeParam(std::numeric_limits::quiet_NaN()), + TypeParam(std::numeric_limits::infinity()), + TypeParam(-std::numeric_limits::infinity()), + TypeParam(1.0e+20f), TypeParam(-1.0e+20f)}; + + std::initializer_list Y_shape{1, 1, 1, 3}; + + test.AddInput("X", X_shape, X_data); + test.AddInput("Grid", Grid_shape, Grid_data); + // Each unsafe coord is sanitized to (-0.5, -0.5); only the bottom-right neighbor + // (pixel(0, 0) = 1.0) is in-bounds with weight 0.5*0.5 = 0.25, others are zeros. + test.AddOutput("Y", Y_shape, {TypeParam(0.25f), TypeParam(0.25f), TypeParam(0.25f)}); + RunCpuOnly(test); +} + +TEST(GridSampleCustomTestFloatOnly, test_grid_sample_20_4D_cubic_reflection_nan_inf_coords) { + // Cubic interpolation also goes through static_cast(std::floor(x)) - 1. + // Cover the NaN / +Inf / -Inf paths through the cubic kernel; constant-valued + // image makes the output trivially 1.0 regardless of which 4x4 neighborhood is + // selected after sanitization. + OpTester test("GridSample", 20); + test.AddAttribute("mode", std::string("cubic")); + test.AddAttribute("padding_mode", std::string("reflection")); + test.AddAttribute("align_corners", int64_t{0}); + + std::initializer_list X_shape{1, 1, 4, 4}; + std::initializer_list X_data{ + 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f}; + + std::initializer_list Grid_shape{1, 1, 3, 2}; + std::initializer_list Grid_data{ + std::numeric_limits::quiet_NaN(), + std::numeric_limits::quiet_NaN(), + std::numeric_limits::infinity(), + -std::numeric_limits::infinity(), + -std::numeric_limits::infinity(), + std::numeric_limits::infinity()}; + + std::initializer_list Y_shape{1, 1, 1, 3}; + + test.AddInput("X", X_shape, X_data); + test.AddInput("Grid", Grid_shape, Grid_data); + test.AddOutput("Y", Y_shape, {1.0f, 1.0f, 1.0f}); + RunCpuOnly(test); +} + +TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_5D_linear_reflection_extreme_coords) { + // 3D trilinear path: exercises std::floor cast for x, y, and z with extreme + // finite coordinates. Sanitization replaces the unsafe components with the + // lower borders before any int64 cast. + OpTester test("GridSample", 20); + test.AddAttribute("mode", std::string("linear")); + test.AddAttribute("padding_mode", std::string("reflection")); + test.AddAttribute("align_corners", int64_t{0}); + + std::initializer_list X_shape{1, 1, 2, 2, 2}; + std::initializer_list X_data{ + TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f), + TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f)}; + + std::initializer_list Grid_shape{1, 1, 1, 2, 3}; + std::initializer_list Grid_data{ + TypeParam(1.0e+20f), TypeParam(1.0e+20f), TypeParam(1.0e+20f), + TypeParam(-1.0e+20f), TypeParam(-1.0e+20f), TypeParam(-1.0e+20f)}; + + std::initializer_list Y_shape{1, 1, 1, 1, 2}; + + test.AddInput("X", X_shape, X_data); + test.AddInput("Grid", Grid_shape, Grid_data); + // Constant-valued image: trilinear interpolation of all-1.0 neighborhood is 1.0. + test.AddOutput("Y", Y_shape, {TypeParam(1.0f), TypeParam(1.0f)}); + RunCpuOnly(test); +} + +TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_5D_nearest_reflection_nan_inf_coords) { + // 3D path with NaN / Inf / -Inf in different spatial dimensions. Verifies + // that the 3D sanitization branch handles non-finite values along any axis. + OpTester test("GridSample", 20); + test.AddAttribute("mode", std::string("nearest")); + test.AddAttribute("padding_mode", std::string("reflection")); + test.AddAttribute("align_corners", int64_t{0}); + + std::initializer_list X_shape{1, 1, 2, 2, 2}; + std::initializer_list X_data{ + TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f), + TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f)}; + + std::initializer_list Grid_shape{1, 1, 1, 2, 3}; + std::initializer_list Grid_data{ + TypeParam(std::numeric_limits::quiet_NaN()), + TypeParam(std::numeric_limits::infinity()), + TypeParam(-std::numeric_limits::infinity()), + TypeParam(std::numeric_limits::infinity()), + TypeParam(std::numeric_limits::quiet_NaN()), + TypeParam(-std::numeric_limits::infinity())}; + + std::initializer_list Y_shape{1, 1, 1, 1, 2}; + + test.AddInput("X", X_shape, X_data); + test.AddInput("Grid", Grid_shape, Grid_data); + test.AddOutput("Y", Y_shape, {TypeParam(1.0f), TypeParam(1.0f)}); + RunCpuOnly(test); +} + +TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_nearest_reflection_align_corners_extreme) { + // align_corners=1 on a non-degenerate (3x3) image. With align_corners=1 the + // lower border becomes 0 (not -0.5), so unsafe coords are sanitized to (0, 0) + // and resolve to the top-left pixel of the image. + OpTester test("GridSample", 20); + test.AddAttribute("mode", std::string("nearest")); + test.AddAttribute("padding_mode", std::string("reflection")); + test.AddAttribute("align_corners", int64_t{1}); + + std::initializer_list X_shape{1, 1, 3, 3}; + std::initializer_list X_data{ + TypeParam(1.0f), TypeParam(2.0f), TypeParam(3.0f), + TypeParam(4.0f), TypeParam(5.0f), TypeParam(6.0f), + TypeParam(7.0f), TypeParam(8.0f), TypeParam(9.0f)}; + + std::initializer_list Grid_shape{1, 1, 2, 2}; + std::initializer_list Grid_data{ + TypeParam(1.0e+20f), TypeParam(1.0e+20f), + TypeParam(std::numeric_limits::quiet_NaN()), + TypeParam(-std::numeric_limits::infinity())}; + + std::initializer_list Y_shape{1, 1, 1, 2}; + + test.AddInput("X", X_shape, X_data); + test.AddInput("Grid", Grid_shape, Grid_data); + // Both unsafe coords sanitize to (0, 0) -> pixel(0, 0) = 1.0. + test.AddOutput("Y", Y_shape, {TypeParam(1.0f), TypeParam(1.0f)}); + RunCpuOnly(test); +} + +TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_nearest_reflection_negative_only_extreme) { + // Asymmetry: all extreme coordinates are negative. Sanitization replaces them + // with x_min/y_min = -0.5, and nearbyint(-0.5) rounds to 0 (banker's rounding), + // so each output samples pixel(0, 0) of a non-constant image. + OpTester test("GridSample", 20); + test.AddAttribute("mode", std::string("nearest")); + test.AddAttribute("padding_mode", std::string("reflection")); + test.AddAttribute("align_corners", int64_t{0}); + + std::initializer_list X_shape{1, 1, 3, 3}; + std::initializer_list X_data{ + TypeParam(1.0f), TypeParam(2.0f), TypeParam(3.0f), + TypeParam(4.0f), TypeParam(5.0f), TypeParam(6.0f), + TypeParam(7.0f), TypeParam(8.0f), TypeParam(9.0f)}; + + std::initializer_list Grid_shape{1, 1, 2, 2}; + std::initializer_list Grid_data{ + TypeParam(-1.0e+20f), TypeParam(-1.0e+20f), + TypeParam(-std::numeric_limits::infinity()), + TypeParam(-std::numeric_limits::infinity())}; + + std::initializer_list Y_shape{1, 1, 1, 2}; + + test.AddInput("X", X_shape, X_data); + test.AddInput("Grid", Grid_shape, Grid_data); + // Sanitized to (-0.5, -0.5); nearbyint -> (0, 0); pixel(0, 0) = 1.0. + test.AddOutput("Y", Y_shape, {TypeParam(1.0f), TypeParam(1.0f)}); + RunCpuOnly(test); +} + +TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_nearest_reflection_mixed_normal_pathological) { + // Mixed normal and pathological grid coordinates in the same call. Validates + // that the sanitization only replaces unsafe values and leaves normal grid + // points untouched, sampling them correctly from a non-constant image. + OpTester test("GridSample", 20); + test.AddAttribute("mode", std::string("nearest")); + test.AddAttribute("padding_mode", std::string("reflection")); + test.AddAttribute("align_corners", int64_t{1}); + + std::initializer_list X_shape{1, 1, 3, 3}; + std::initializer_list X_data{ + TypeParam(1.0f), TypeParam(2.0f), TypeParam(3.0f), + TypeParam(4.0f), TypeParam(5.0f), TypeParam(6.0f), + TypeParam(7.0f), TypeParam(8.0f), TypeParam(9.0f)}; + + // align_corners=1 on a 3x3 image maps normalized [-1, 1] -> pixel coords [0, 2]. + // Mix four points: center, top-left, NaN (sanitized -> (0,0)), and asymmetric + // extreme (sanitized -> (0,0)). + std::initializer_list Grid_shape{1, 1, 4, 2}; + std::initializer_list Grid_data{ + TypeParam(0.0f), TypeParam(0.0f), // -> pixel(1, 1) = 5 + TypeParam(-1.0f), TypeParam(-1.0f), // -> pixel(0, 0) = 1 + TypeParam(std::numeric_limits::quiet_NaN()), + TypeParam(std::numeric_limits::quiet_NaN()), // sanitized -> pixel(0, 0) = 1 + TypeParam(1.0e+20f), TypeParam(-1.0e+20f)}; // sanitized -> pixel(0, 0) = 1 + + std::initializer_list Y_shape{1, 1, 1, 4}; + + test.AddInput("X", X_shape, X_data); + test.AddInput("Grid", Grid_shape, Grid_data); + test.AddOutput("Y", Y_shape, + {TypeParam(5.0f), TypeParam(1.0f), TypeParam(1.0f), TypeParam(1.0f)}); + RunCpuOnly(test); +} + } // namespace test } // namespace onnxruntime From 6229b123abec69f96a4801ebab0c52c6fa2da8af Mon Sep 17 00:00:00 2001 From: Gopalakrishnan Nallasamy Date: Fri, 1 May 2026 13:09:30 -0700 Subject: [PATCH 6/6] Apply clang-format to grid_sample_test_custom.cc --- .../test/providers/cpu/tensor/grid_sample_test_custom.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/onnxruntime/test/providers/cpu/tensor/grid_sample_test_custom.cc b/onnxruntime/test/providers/cpu/tensor/grid_sample_test_custom.cc index 16b622359c150..dd23b76d8275d 100644 --- a/onnxruntime/test/providers/cpu/tensor/grid_sample_test_custom.cc +++ b/onnxruntime/test/providers/cpu/tensor/grid_sample_test_custom.cc @@ -563,8 +563,8 @@ TYPED_TEST(GridSampleCustomTest, test_grid_sample_20_4D_nearest_reflection_mixed // extreme (sanitized -> (0,0)). std::initializer_list Grid_shape{1, 1, 4, 2}; std::initializer_list Grid_data{ - TypeParam(0.0f), TypeParam(0.0f), // -> pixel(1, 1) = 5 - TypeParam(-1.0f), TypeParam(-1.0f), // -> pixel(0, 0) = 1 + TypeParam(0.0f), TypeParam(0.0f), // -> pixel(1, 1) = 5 + TypeParam(-1.0f), TypeParam(-1.0f), // -> pixel(0, 0) = 1 TypeParam(std::numeric_limits::quiet_NaN()), TypeParam(std::numeric_limits::quiet_NaN()), // sanitized -> pixel(0, 0) = 1 TypeParam(1.0e+20f), TypeParam(-1.0e+20f)}; // sanitized -> pixel(0, 0) = 1