Skip to content

Commit 35542e0

Browse files
committed
Fix int32 overflow in max_pool3d forward kernel
Widen parameters and variables in MaxPool3dKernelFunctor and max_pool3d_with_indices_out_template from int to int64_t to prevent overflow when computing strides for large tensors. This mirrors the backward kernel fix from #3558 The forward kernel was partially protected by int64_t local variables and explicit casts at usage sites, so the existing test shape [70, 32, 100, 100, 100] did not trigger failures. However, the stride values themselves (e.g. in_batch_stride = features * T * H * W) were computed as int, which silently overflows for shapes where a single stride exceeds INT32_MAX (e.g. [2, 2200, 100, 100, 100] gives in_batch_stride = 2.2B). Changes: - Fix typo: MaxPool3dKerenlFunctor -> MaxPool3dKernelFunctor - Widen dimension and stride params/members to int64_t (kernel, stride, padding, and dilation params remain int) - Remove now-redundant (int64_t) casts in operator() - Add test_pool3d_fwd_large_size_int64 with a shape that overflows int32 batch strides in the forward pass
1 parent 42e64e2 commit 35542e0

2 files changed

Lines changed: 100 additions & 62 deletions

File tree

src/ATen/native/xpu/sycl/DilatedMaxPool3d.cpp

Lines changed: 62 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ DISABLE_RETURN_TYPE_WARNING_BEGIN
3333
namespace at::native::xpu {
3434

3535
template <typename scalar_t, bool channels_last_>
36-
struct MaxPool3dKerenlFunctor {
36+
struct MaxPool3dKernelFunctor {
3737
void operator()(sycl::nd_item<1> item) const {
3838
auto outputIndex = item.get_global_id(0);
3939
if (outputIndex < OutputSize_) {
@@ -62,9 +62,9 @@ struct MaxPool3dKerenlFunctor {
6262
int tStart = oTime * dT_ - pT_;
6363
int hStart = oRow * dH_ - pH_;
6464
int wStart = oColumn * dW_ - pW_;
65-
int tEnd = std::min(tStart + (kT_ - 1) * dilationT_ + 1, itime_);
66-
int hEnd = std::min(hStart + (kH_ - 1) * dilationH_ + 1, iheight_);
67-
int wEnd = std::min(wStart + (kW_ - 1) * dilationW_ + 1, iwidth_);
65+
int tEnd = std::min(tStart + (kT_ - 1) * dilationT_ + 1, static_cast<int>(itime_));
66+
int hEnd = std::min(hStart + (kH_ - 1) * dilationH_ + 1, static_cast<int>(iheight_));
67+
int wEnd = std::min(wStart + (kW_ - 1) * dilationW_ + 1, static_cast<int>(iwidth_));
6868

6969
while (tStart < 0)
7070
tStart += dilationT_;
@@ -78,9 +78,9 @@ struct MaxPool3dKerenlFunctor {
7878
int64_t ioffset;
7979

8080
if constexpr (!channels_last_) {
81-
ioffset = (int64_t)slice * in_cf_c_stride_;
81+
ioffset = slice * in_cf_c_stride_;
8282
} else {
83-
ioffset = ((int64_t)batch * in_batch_stride_) + channel;
83+
ioffset = batch * in_batch_stride_ + channel;
8484
}
8585

8686
scalar_t max = at::numeric_limits<scalar_t>::lower_bound();
@@ -89,7 +89,7 @@ struct MaxPool3dKerenlFunctor {
8989
for (int h = hStart; h < hEnd; h += dilationH_) {
9090
for (int w = wStart; w < wEnd; w += dilationW_) {
9191
scalar_t val;
92-
int index = t * in_hw_stride_ + h * iwidth_ + w;
92+
int64_t index = t * in_hw_stride_ + h * iwidth_ + w;
9393
if constexpr (!channels_last_) {
9494
val = inputData_[ioffset + index];
9595
} else {
@@ -107,29 +107,29 @@ struct MaxPool3dKerenlFunctor {
107107

108108
int64_t out_index;
109109
if constexpr (!channels_last_) {
110-
out_index = (int64_t)slice * out_cf_c_stride_ +
110+
out_index = slice * out_cf_c_stride_ +
111111
oTime * out_cf_d_stride_ + oRow * owidth_ + oColumn;
112112
} else {
113-
out_index = (int64_t)batch * out_batch_stride_ +
113+
out_index = batch * out_batch_stride_ +
114114
oTime * out_cl_d_stride_ + oRow * out_cl_h_stride_ +
115115
oColumn * features_ + channel;
116116
}
117117
outputData_[out_index] = max;
118118
indicesData_[out_index] = maxIndex;
119119
}
120120
}
121-
MaxPool3dKerenlFunctor(
121+
MaxPool3dKernelFunctor(
122122
const scalar_t* inputData,
123123
scalar_t* outputData,
124124
int64_t* indicesData,
125-
int features,
126-
int itime,
127-
int iheight,
128-
int iwidth,
129-
int obatch,
130-
int otime,
131-
int oheight,
132-
int owidth,
125+
int64_t features,
126+
int64_t itime,
127+
int64_t iheight,
128+
int64_t iwidth,
129+
int64_t obatch,
130+
int64_t otime,
131+
int64_t oheight,
132+
int64_t owidth,
133133
int kT,
134134
int kH,
135135
int kW,
@@ -143,17 +143,17 @@ struct MaxPool3dKerenlFunctor {
143143
int dilationH,
144144
int dilationW,
145145
int64_t OutputSize,
146-
int out_cf_d_stride,
147-
int out_cf_c_stride,
148-
int in_cf_d_stride,
149-
int in_cf_c_stride,
150-
int out_cl_h_stride,
151-
int out_cl_d_stride,
152-
int in_cl_h_stride,
153-
int in_cl_d_stride,
154-
int in_batch_stride,
155-
int out_batch_stride,
156-
int in_hw_stride)
146+
int64_t out_cf_d_stride,
147+
int64_t out_cf_c_stride,
148+
int64_t in_cf_d_stride,
149+
int64_t in_cf_c_stride,
150+
int64_t out_cl_h_stride,
151+
int64_t out_cl_d_stride,
152+
int64_t in_cl_h_stride,
153+
int64_t in_cl_d_stride,
154+
int64_t in_batch_stride,
155+
int64_t out_batch_stride,
156+
int64_t in_hw_stride)
157157
: inputData_(inputData),
158158
outputData_(outputData),
159159
indicesData_(indicesData),
@@ -194,14 +194,14 @@ struct MaxPool3dKerenlFunctor {
194194
const scalar_t* inputData_;
195195
scalar_t* outputData_;
196196
int64_t* indicesData_;
197-
int features_;
198-
int itime_;
199-
int iheight_;
200-
int iwidth_;
201-
int obatch_;
202-
int otime_;
203-
int oheight_;
204-
int owidth_;
197+
int64_t features_;
198+
int64_t itime_;
199+
int64_t iheight_;
200+
int64_t iwidth_;
201+
int64_t obatch_;
202+
int64_t otime_;
203+
int64_t oheight_;
204+
int64_t owidth_;
205205
int kT_;
206206
int kH_;
207207
int kW_;
@@ -215,32 +215,32 @@ struct MaxPool3dKerenlFunctor {
215215
int dilationH_;
216216
int dilationW_;
217217
int64_t OutputSize_;
218-
int out_cf_d_stride_;
219-
int out_cf_c_stride_;
220-
int in_cf_d_stride_;
221-
int in_cf_c_stride_;
222-
int out_cl_h_stride_;
223-
int out_cl_d_stride_;
224-
int in_cl_h_stride_;
225-
int in_cl_d_stride_;
226-
int in_batch_stride_;
227-
int out_batch_stride_;
228-
int in_hw_stride_;
218+
int64_t out_cf_d_stride_;
219+
int64_t out_cf_c_stride_;
220+
int64_t in_cf_d_stride_;
221+
int64_t in_cf_c_stride_;
222+
int64_t out_cl_h_stride_;
223+
int64_t out_cl_d_stride_;
224+
int64_t in_cl_h_stride_;
225+
int64_t in_cl_d_stride_;
226+
int64_t in_batch_stride_;
227+
int64_t out_batch_stride_;
228+
int64_t in_hw_stride_;
229229
};
230230

231231
template <typename scalar_t, bool channels_last>
232232
void max_pool3d_with_indices_out_template(
233233
const scalar_t* inputData,
234234
scalar_t* outputData,
235235
int64_t* indicesData,
236-
int features,
237-
int itime,
238-
int iheight,
239-
int iwidth,
240-
int obatch,
241-
int otime,
242-
int oheight,
243-
int owidth,
236+
int64_t features,
237+
int64_t itime,
238+
int64_t iheight,
239+
int64_t iwidth,
240+
int64_t obatch,
241+
int64_t otime,
242+
int64_t oheight,
243+
int64_t owidth,
244244
int kT,
245245
int kH,
246246
int kW,
@@ -255,9 +255,9 @@ void max_pool3d_with_indices_out_template(
255255
int dilationW) {
256256
int64_t OutputSize = obatch * features * otime * oheight * owidth;
257257

258-
int out_cf_d_stride = 0, out_cf_c_stride = 0, in_cf_d_stride = 0,
258+
int64_t out_cf_d_stride = 0, out_cf_c_stride = 0, in_cf_d_stride = 0,
259259
in_cf_c_stride = 0;
260-
int out_cl_h_stride = 0, out_cl_d_stride = 0, in_cl_h_stride = 0,
260+
int64_t out_cl_h_stride = 0, out_cl_d_stride = 0, in_cl_h_stride = 0,
261261
in_cl_d_stride = 0;
262262
if constexpr (!channels_last) {
263263
out_cf_d_stride = owidth * oheight;
@@ -268,10 +268,10 @@ void max_pool3d_with_indices_out_template(
268268
out_cl_h_stride = owidth * features;
269269
out_cl_d_stride = oheight * out_cl_h_stride;
270270
}
271-
auto in_batch_stride = itime * iheight * iwidth * features;
272-
auto out_batch_stride = otime * oheight * owidth * features;
273-
auto in_hw_stride = iwidth * iheight;
274-
MaxPool3dKerenlFunctor<scalar_t, channels_last> kfn(
271+
int64_t in_batch_stride = itime * iheight * iwidth * features;
272+
int64_t out_batch_stride = otime * oheight * owidth * features;
273+
int64_t in_hw_stride = iwidth * iheight;
274+
MaxPool3dKernelFunctor<scalar_t, channels_last> kfn(
275275
inputData,
276276
outputData,
277277
indicesData,

test/xpu/nn/test_pooling_xpu.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,44 @@ def _test_pool3d_large_size_int64(self, device):
549549
TestPoolingNNDeviceType.test_pool3d_large_size_int64 = _test_pool3d_large_size_int64
550550

551551

552+
@largeTensorTest("20GB", device=device_type)
553+
@largeTensorTest("40GB", "cpu")
554+
def _test_pool3d_fwd_large_size_int64(self, device):
555+
"""Test that the forward pass of max_pool3d handles int64 strides correctly.
556+
557+
Exercises two overflow scenarios:
558+
- channels_last_3d: in_batch_stride = C * D * H * W > INT32_MAX
559+
(shape [2, 2200, 100, 100, 100] → stride 2.2B).
560+
- contiguous: in_cf_c_stride = D * H * W > INT32_MAX
561+
(shape [1, 2, 1300, 1300, 1300] → stride 2.197B).
562+
The existing test_pool3d_large_size_int64 does not trigger these
563+
because its per-stride values fit in int32.
564+
"""
565+
cases = [
566+
# (shape, memory_format)
567+
((2, 2200, 100, 100, 100), torch.channels_last_3d),
568+
((1, 2, 1300, 1300, 1300), torch.contiguous_format),
569+
]
570+
for shape, memory_format in cases:
571+
with self.subTest(memory_format=memory_format):
572+
x = torch.randn(*shape, dtype=torch.half, device=device).to(
573+
memory_format=memory_format
574+
)
575+
y = torch.nn.functional.max_pool3d(x, 5)
576+
torch.get_device_module(device).synchronize()
577+
578+
ref_x = x.detach().cpu().float().contiguous()
579+
ref_y = torch.nn.functional.max_pool3d(ref_x, 5)
580+
581+
self.assertEqual(y, ref_y, exact_dtype=False)
582+
del x, y, ref_x, ref_y
583+
584+
585+
TestPoolingNNDeviceType.test_pool3d_fwd_large_size_int64 = (
586+
_test_pool3d_fwd_large_size_int64
587+
)
588+
589+
552590
# Upstream test_pooling.py:test_pooling_large uses hard-coded device="cuda"
553591
# and torch.cuda.synchronize(); resolve both via the test-supplied `device`
554592
# (set by instantiate_device_type_tests) so the body is not bound to a

0 commit comments

Comments
 (0)