mirror of
https://github.com/opencv/opencv.git
synced 2026-09-11 04:43:22 -05:00
Fix int usage for pixbuf when double is asked for.
When chtype is double (used by bicubic64fC1 .. bicubic64fC4), std::is_same_v<double, float> evaluated to false. As a result, buftype erroneously defaulted to int, and pixbuf was allocated as int pixbuf[NCHANNELS][4]. That could trigger out of bound integer computations.
This commit is contained in:
@@ -7170,67 +7170,67 @@ static void bicubicFetchPixels(const _Tp* src, size_t srcstep, Size size, int cn
|
||||
#undef BICUBIC_PROCESS_INLIERS_C1_SCALAR
|
||||
#define BICUBIC_PROCESS_INLIERS_C1_SCALAR(row) \
|
||||
srcrow = (const chtype*)((const uint8_t*)src + row*srcstep + tl_ofs); \
|
||||
V0 = float(srcrow[0]); \
|
||||
V1 = float(srcrow[1]); \
|
||||
V2 = float(srcrow[2]); \
|
||||
V3 = float(srcrow[3]); \
|
||||
V0 = acctype(srcrow[0]); \
|
||||
V1 = acctype(srcrow[1]); \
|
||||
V2 = acctype(srcrow[2]); \
|
||||
V3 = acctype(srcrow[3]); \
|
||||
BICUBIC_UPDATE_ACC(acc_r, V0, V1, V2, V3, wy##row)
|
||||
|
||||
#undef BICUBIC_PROCESS_INLIERS_C2_SCALAR
|
||||
#define BICUBIC_PROCESS_INLIERS_C2_SCALAR(row) \
|
||||
srcrow = (const chtype*)((const uint8_t*)src + row*srcstep + tl_ofs); \
|
||||
V0 = float(srcrow[0]); \
|
||||
V1 = float(srcrow[2]); \
|
||||
V2 = float(srcrow[4]); \
|
||||
V3 = float(srcrow[6]); \
|
||||
V0 = acctype(srcrow[0]); \
|
||||
V1 = acctype(srcrow[2]); \
|
||||
V2 = acctype(srcrow[4]); \
|
||||
V3 = acctype(srcrow[6]); \
|
||||
BICUBIC_UPDATE_ACC(acc_r, V0, V1, V2, V3, wy##row); \
|
||||
V0 = float(srcrow[1]); \
|
||||
V1 = float(srcrow[3]); \
|
||||
V2 = float(srcrow[5]); \
|
||||
V3 = float(srcrow[7]); \
|
||||
V0 = acctype(srcrow[1]); \
|
||||
V1 = acctype(srcrow[3]); \
|
||||
V2 = acctype(srcrow[5]); \
|
||||
V3 = acctype(srcrow[7]); \
|
||||
BICUBIC_UPDATE_ACC(acc_g, V0, V1, V2, V3, wy##row)
|
||||
|
||||
#undef BICUBIC_PROCESS_INLIERS_C3_SCALAR
|
||||
#define BICUBIC_PROCESS_INLIERS_C3_SCALAR(row) \
|
||||
srcrow = (const chtype*)((const uint8_t*)src + row*srcstep + tl_ofs); \
|
||||
V0 = float(srcrow[0]); \
|
||||
V1 = float(srcrow[3]); \
|
||||
V2 = float(srcrow[6]); \
|
||||
V3 = float(srcrow[9]); \
|
||||
V0 = acctype(srcrow[0]); \
|
||||
V1 = acctype(srcrow[3]); \
|
||||
V2 = acctype(srcrow[6]); \
|
||||
V3 = acctype(srcrow[9]); \
|
||||
BICUBIC_UPDATE_ACC(acc_r, V0, V1, V2, V3, wy##row); \
|
||||
V0 = float(srcrow[1]); \
|
||||
V1 = float(srcrow[4]); \
|
||||
V2 = float(srcrow[7]); \
|
||||
V3 = float(srcrow[10]); \
|
||||
V0 = acctype(srcrow[1]); \
|
||||
V1 = acctype(srcrow[4]); \
|
||||
V2 = acctype(srcrow[7]); \
|
||||
V3 = acctype(srcrow[10]); \
|
||||
BICUBIC_UPDATE_ACC(acc_g, V0, V1, V2, V3, wy##row); \
|
||||
V0 = float(srcrow[2]); \
|
||||
V1 = float(srcrow[5]); \
|
||||
V2 = float(srcrow[8]); \
|
||||
V3 = float(srcrow[11]); \
|
||||
V0 = acctype(srcrow[2]); \
|
||||
V1 = acctype(srcrow[5]); \
|
||||
V2 = acctype(srcrow[8]); \
|
||||
V3 = acctype(srcrow[11]); \
|
||||
BICUBIC_UPDATE_ACC(acc_b, V0, V1, V2, V3, wy##row)
|
||||
|
||||
#undef BICUBIC_PROCESS_INLIERS_C4_SCALAR
|
||||
#define BICUBIC_PROCESS_INLIERS_C4_SCALAR(row) \
|
||||
srcrow = (const chtype*)((const uint8_t*)src + row*srcstep + tl_ofs); \
|
||||
V0 = float(srcrow[0]); \
|
||||
V1 = float(srcrow[4]); \
|
||||
V2 = float(srcrow[8]); \
|
||||
V3 = float(srcrow[12]); \
|
||||
V0 = acctype(srcrow[0]); \
|
||||
V1 = acctype(srcrow[4]); \
|
||||
V2 = acctype(srcrow[8]); \
|
||||
V3 = acctype(srcrow[12]); \
|
||||
BICUBIC_UPDATE_ACC(acc_r, V0, V1, V2, V3, wy##row); \
|
||||
V0 = float(srcrow[1]); \
|
||||
V1 = float(srcrow[5]); \
|
||||
V2 = float(srcrow[9]); \
|
||||
V3 = float(srcrow[13]); \
|
||||
V0 = acctype(srcrow[1]); \
|
||||
V1 = acctype(srcrow[5]); \
|
||||
V2 = acctype(srcrow[9]); \
|
||||
V3 = acctype(srcrow[13]); \
|
||||
BICUBIC_UPDATE_ACC(acc_g, V0, V1, V2, V3, wy##row); \
|
||||
V0 = float(srcrow[2]); \
|
||||
V1 = float(srcrow[6]); \
|
||||
V2 = float(srcrow[10]); \
|
||||
V3 = float(srcrow[14]); \
|
||||
V0 = acctype(srcrow[2]); \
|
||||
V1 = acctype(srcrow[6]); \
|
||||
V2 = acctype(srcrow[10]); \
|
||||
V3 = acctype(srcrow[14]); \
|
||||
BICUBIC_UPDATE_ACC(acc_b, V0, V1, V2, V3, wy##row); \
|
||||
V0 = float(srcrow[3]); \
|
||||
V1 = float(srcrow[7]); \
|
||||
V2 = float(srcrow[11]); \
|
||||
V3 = float(srcrow[15]); \
|
||||
V0 = acctype(srcrow[3]); \
|
||||
V1 = acctype(srcrow[7]); \
|
||||
V2 = acctype(srcrow[11]); \
|
||||
V3 = acctype(srcrow[15]); \
|
||||
BICUBIC_UPDATE_ACC(acc_a, V0, V1, V2, V3, wy##row)
|
||||
|
||||
template<typename chtype, int NCHANNELS>
|
||||
@@ -7242,7 +7242,8 @@ static void bicubicRef(const float* srcx, const float* srcy, int len,
|
||||
float A = params ? *params : defaultA;
|
||||
|
||||
constexpr int BPP = int(NCHANNELS*sizeof(dst[0]));
|
||||
using buftype = std::conditional_t<std::is_same_v<chtype, float>, float, int>;
|
||||
using buftype = std::conditional_t<std::is_floating_point_v<chtype>, chtype, int>;
|
||||
using acctype = std::conditional_t<std::is_same_v<chtype, double>, double, float>;
|
||||
using pixtype = std::conditional_t<NCHANNELS == 1, chtype, Vec<chtype, NCHANNELS>>;
|
||||
|
||||
pixtype bval = borderVal ? *(pixtype*)borderVal : pixtype();
|
||||
@@ -7250,7 +7251,7 @@ static void bicubicRef(const float* srcx, const float* srcy, int len,
|
||||
for (int i = 0; i < len; i++, dst += NCHANNELS) {
|
||||
buftype pixbuf[NCHANNELS][4];
|
||||
int tl_x, tl_y, tl_ofs, goodx[4];
|
||||
float V0, V1, V2, V3;
|
||||
acctype V0, V1, V2, V3;
|
||||
float wx0, wx1, wx2, wx3, wy0, wy1, wy2, wy3;
|
||||
float xs = srcx[i], ys = srcy[i];
|
||||
|
||||
@@ -7260,14 +7261,14 @@ static void bicubicRef(const float* srcx, const float* srcy, int len,
|
||||
if (code > 0) {
|
||||
const chtype* srcrow;
|
||||
if constexpr (NCHANNELS == 1) {
|
||||
float acc_r = 0.f;
|
||||
acctype acc_r = 0;
|
||||
BICUBIC_PROCESS_INLIERS_C1_SCALAR(0);
|
||||
BICUBIC_PROCESS_INLIERS_C1_SCALAR(1);
|
||||
BICUBIC_PROCESS_INLIERS_C1_SCALAR(2);
|
||||
BICUBIC_PROCESS_INLIERS_C1_SCALAR(3);
|
||||
dst[0] = saturate_cast<chtype>(acc_r);
|
||||
} else if constexpr (NCHANNELS == 2) {
|
||||
float acc_r = 0.f, acc_g = 0.f;
|
||||
acctype acc_r = 0, acc_g = 0;
|
||||
BICUBIC_PROCESS_INLIERS_C2_SCALAR(0);
|
||||
BICUBIC_PROCESS_INLIERS_C2_SCALAR(1);
|
||||
BICUBIC_PROCESS_INLIERS_C2_SCALAR(2);
|
||||
@@ -7275,7 +7276,7 @@ static void bicubicRef(const float* srcx, const float* srcy, int len,
|
||||
dst[0] = saturate_cast<chtype>(acc_r);
|
||||
dst[1] = saturate_cast<chtype>(acc_g);
|
||||
} else if constexpr (NCHANNELS == 3) {
|
||||
float acc_r = 0.f, acc_g = 0.f, acc_b = 0.f;
|
||||
acctype acc_r = 0, acc_g = 0, acc_b = 0;
|
||||
BICUBIC_PROCESS_INLIERS_C3_SCALAR(0);
|
||||
BICUBIC_PROCESS_INLIERS_C3_SCALAR(1);
|
||||
BICUBIC_PROCESS_INLIERS_C3_SCALAR(2);
|
||||
@@ -7284,7 +7285,7 @@ static void bicubicRef(const float* srcx, const float* srcy, int len,
|
||||
dst[1] = saturate_cast<chtype>(acc_g);
|
||||
dst[2] = saturate_cast<chtype>(acc_b);
|
||||
} else if constexpr (NCHANNELS == 4) {
|
||||
float acc_r = 0.f, acc_g = 0.f, acc_b = 0.f, acc_a = 0.f;
|
||||
acctype acc_r = 0, acc_g = 0, acc_b = 0, acc_a = 0;
|
||||
BICUBIC_PROCESS_INLIERS_C4_SCALAR(0);
|
||||
BICUBIC_PROCESS_INLIERS_C4_SCALAR(1);
|
||||
BICUBIC_PROCESS_INLIERS_C4_SCALAR(2);
|
||||
@@ -7300,7 +7301,7 @@ static void bicubicRef(const float* srcx, const float* srcy, int len,
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
float acc[NCHANNELS] = {};
|
||||
acctype acc[NCHANNELS] = {};
|
||||
float wys[] = {wy0, wy1, wy2, wy3};
|
||||
const chtype* defVal = borderType == BORDER_TRANSPARENT ? dst : borderVal;
|
||||
for (int row = 0; row < 4; row++) {
|
||||
@@ -7308,10 +7309,10 @@ static void bicubicRef(const float* srcx, const float* srcy, int len,
|
||||
goodx, row, &pixbuf[0][0], 1, borderType, defVal);
|
||||
float wy = wys[row];
|
||||
for (int c = 0; c < NCHANNELS; c++) {
|
||||
V0 = float(pixbuf[c][0]);
|
||||
V1 = float(pixbuf[c][1]);
|
||||
V2 = float(pixbuf[c][2]);
|
||||
V3 = float(pixbuf[c][3]);
|
||||
V0 = acctype(pixbuf[c][0]);
|
||||
V1 = acctype(pixbuf[c][1]);
|
||||
V2 = acctype(pixbuf[c][2]);
|
||||
V3 = acctype(pixbuf[c][3]);
|
||||
BICUBIC_UPDATE_ACC(acc[c], V0, V1, V2, V3, wy);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1123,6 +1123,30 @@ static void rotation2affine(float scale, float angle, float cx, float cy, float*
|
||||
M[3] = -scale*sa; M[4] = scale*ca; M[5] = scale*(cx*sa - cy*ca) + cy;
|
||||
}
|
||||
|
||||
TEST(Imgproc_Warping, Bicubic64F) {
|
||||
// 1. Values exceeding INT_MAX: triggers UBSan float-cast-overflow if buftype is int
|
||||
{
|
||||
cv::Mat src(10, 10, CV_64FC1, cv::Scalar(1e100));
|
||||
cv::Mat dst;
|
||||
cv::Matx23f M(1.f, 0.f, 0.f, 0.f, 1.f, 0.f);
|
||||
EXPECT_NO_THROW(cv::warpAffine(src, dst, M, cv::Size(20, 20),
|
||||
cv::INTER_CUBIC, cv::BORDER_CONSTANT, cv::Scalar(0.0)));
|
||||
ASSERT_EQ(dst.type(), CV_64FC1);
|
||||
EXPECT_DOUBLE_EQ(dst.at<double>(5, 5), 1e100);
|
||||
}
|
||||
// 2. Fractional double values: ensures boundary pixels are not truncated to int
|
||||
{
|
||||
cv::Mat src(10, 10, CV_64FC1, cv::Scalar(1.5));
|
||||
cv::Mat dst;
|
||||
cv::Matx23f M(1.f, 0.f, 0.f, 0.f, 1.f, 0.f);
|
||||
cv::warpAffine(src, dst, M, cv::Size(20, 20),
|
||||
cv::INTER_CUBIC, cv::BORDER_CONSTANT, cv::Scalar(1.5));
|
||||
ASSERT_EQ(dst.type(), CV_64FC1);
|
||||
// Boundary pixels (x=9, y=9) previously truncated (int)1.5 -> 1.0; now they preserve 1.5:
|
||||
EXPECT_DOUBLE_EQ(dst.at<double>(9, 9), 1.5);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Imgproc_Warping, DISABLED_playground)
|
||||
{
|
||||
int imgtype = CV_32F;
|
||||
|
||||
Reference in New Issue
Block a user