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:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user