1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-21 19:33:03 +04:00

core(ocl): fix out-of-bounds read and SIGFPE in predictOptimalVectorWidth for new depths

predictOptimalVectorWidth() built its vectorWidths table with 8 entries
(depths CV_8U..CV_16F), but checkOptimalVectorWidth() indexes it by depth.
The 5.x depths CV_16BF, CV_Bool, CV_64U, CV_64S and CV_32U therefore read
past the end of the array; the garbage value can slip past the ckercn <= 0
guard, and the divider normalization loop then shifts the divider to zero,
so "offsets[i] % dividers[i]" raises SIGFPE. The failure is allocation
dependent and shows up as a sequence-dependent crash, e.g. in the OpenCL
Norm tests for CV_32U (cv::norm on a UMat reaches this via ocl_sum, which
calls predictOptimalVectorWidth before its own depth guard bails out).

Size the table to CV_DEPTH_MAX so every depth is in bounds and map the new
fixed-size integer depths to their natural OpenCL vector widths; CV_16BF
has no OpenCL vector type and stays scalar. Add a regression test covering
all depths.
This commit is contained in:
Jesus Armando Anaya
2026-06-21 16:39:40 -07:00
parent 6d2cd14bb2
commit 7334957476
2 changed files with 35 additions and 4 deletions
+11 -4
View File
@@ -7229,10 +7229,17 @@ int predictOptimalVectorWidth(InputArray src1, InputArray src2, InputArray src3,
{
const ocl::Device & d = ocl::Device::getDefault();
int vectorWidths[] = { d.preferredVectorWidthChar(), d.preferredVectorWidthChar(),
d.preferredVectorWidthShort(), d.preferredVectorWidthShort(),
d.preferredVectorWidthInt(), d.preferredVectorWidthFloat(),
d.preferredVectorWidthDouble(), d.preferredVectorWidthHalf() };
// Indexed by depth: must span CV_DEPTH_MAX. bf16 has no OpenCL vector type.
int vectorWidths[CV_DEPTH_MAX] = {
d.preferredVectorWidthChar(), d.preferredVectorWidthChar(), // CV_8U, CV_8S
d.preferredVectorWidthShort(), d.preferredVectorWidthShort(), // CV_16U, CV_16S
d.preferredVectorWidthInt(), d.preferredVectorWidthFloat(), // CV_32S, CV_32F
d.preferredVectorWidthDouble(), d.preferredVectorWidthHalf(), // CV_64F, CV_16F
1, // CV_16BF
d.preferredVectorWidthChar(), // CV_Bool
d.preferredVectorWidthLong(), d.preferredVectorWidthLong(), // CV_64U, CV_64S
d.preferredVectorWidthInt() // CV_32U
};
// if the device says don't use vectors
if (vectorWidths[0] == 1)
+24
View File
@@ -2124,6 +2124,30 @@ OCL_TEST(Normalize, DISABLED_regression_5876_inplace_change_type)
EXPECT_EQ(0, cvtest::norm(um, uresult, NORM_INF));
}
// Regression: predictOptimalVectorWidth() must handle every depth without
// reading past its per-depth table.
OCL_TEST(Arithm, predictOptimalVectorWidth_all_depths)
{
if (!cv::ocl::useOpenCL())
return;
const int depths[] = { CV_8U, CV_8S, CV_16U, CV_16S, CV_32S, CV_32F, CV_64F,
CV_16F, CV_16BF, CV_Bool, CV_64U, CV_64S, CV_32U };
for (size_t i = 0; i < sizeof(depths) / sizeof(depths[0]); ++i)
{
const int depth = depths[i];
for (int cn = 1; cn <= 4; ++cn)
{
const int type = CV_MAKE_TYPE(depth, cn);
UMat a(11, 13, type), b(11, 13, type);
EXPECT_GE(cv::ocl::predictOptimalVectorWidth(a), 1)
<< "depth=" << depth << " cn=" << cn;
EXPECT_GE(cv::ocl::predictOptimalVectorWidth(a, b), 1)
<< "depth=" << depth << " cn=" << cn;
}
}
}
} } // namespace opencv_test::ocl
#endif // HAVE_OPENCL