Skip to content

Commit 6308739

Browse files
committed
features2d: fixed out of bounds access in SIFT
1 parent 4c81e17 commit 6308739

File tree

2 files changed

+38
-24
lines changed

2 files changed

+38
-24
lines changed

modules/features2d/src/sift.simd.hpp

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ void findScaleSpaceExtrema(
150150

151151
void calcSIFTDescriptor(
152152
const Mat& img, Point2f ptf, float ori, float scl,
153-
int d, int n, Mat& dst, int row
153+
const int d, const int n, Mat& dst, int row
154154
);
155155

156156

@@ -708,7 +708,7 @@ void findScaleSpaceExtrema(
708708

709709
void calcSIFTDescriptor(
710710
const Mat& img, Point2f ptf, float ori, float scl,
711-
int d, int n, Mat& dstMat, int row
711+
const int d, const int n, Mat& dstMat, int row
712712
)
713713
{
714714
CV_TRACE_FUNCTION();
@@ -725,7 +725,10 @@ void calcSIFTDescriptor(
725725
cos_t /= hist_width;
726726
sin_t /= hist_width;
727727

728-
int i, j, k, len = (radius*2+1)*(radius*2+1), histlen = (d+2)*(d+2)*(n+2);
728+
int i, j, k;
729+
const int len = (radius*2+1)*(radius*2+1);
730+
const int len_hist = (d+2)*(d+2)*(n+2);
731+
const int len_ddn = d * d * n;
729732
int rows = img.rows, cols = img.cols;
730733

731734
cv::utils::BufferArea area;
@@ -736,8 +739,8 @@ void calcSIFTDescriptor(
736739
area.allocate(W, len, CV_SIMD_WIDTH);
737740
area.allocate(RBin, len, CV_SIMD_WIDTH);
738741
area.allocate(CBin, len, CV_SIMD_WIDTH);
739-
area.allocate(hist, histlen, CV_SIMD_WIDTH);
740-
area.allocate(rawDst, len, CV_SIMD_WIDTH);
742+
area.allocate(hist, len_hist, CV_SIMD_WIDTH);
743+
area.allocate(rawDst, len_ddn, CV_SIMD_WIDTH);
741744
area.commit();
742745
Mag = Y;
743746

@@ -771,10 +774,10 @@ void calcSIFTDescriptor(
771774
}
772775
}
773776

774-
len = k;
775-
cv::hal::fastAtan2(Y, X, Ori, len, true);
776-
cv::hal::magnitude32f(X, Y, Mag, len);
777-
cv::hal::exp32f(W, W, len);
777+
const int len_left = k;
778+
cv::hal::fastAtan2(Y, X, Ori, len_left, true);
779+
cv::hal::magnitude32f(X, Y, Mag, len_left);
780+
cv::hal::exp32f(W, W, len_left);
778781

779782
k = 0;
780783
#if (CV_SIMD || CV_SIMD_SCALABLE)
@@ -788,7 +791,7 @@ void calcSIFTDescriptor(
788791
const v_int32 __1 = vx_setall_s32(1);
789792
const v_int32 __d_plus_2 = vx_setall_s32(d+2);
790793
const v_int32 __n_plus_2 = vx_setall_s32(n+2);
791-
for( ; k <= len - vecsize; k += vecsize )
794+
for( ; k <= len_left - vecsize; k += vecsize )
792795
{
793796
v_float32 rbin = vx_load_aligned(RBin + k);
794797
v_float32 cbin = vx_load_aligned(CBin + k);
@@ -839,7 +842,7 @@ void calcSIFTDescriptor(
839842
}
840843
}
841844
#endif
842-
for( ; k < len; k++ )
845+
for( ; k < len_left; k++ )
843846
{
844847
float rbin = RBin[k], cbin = CBin[k];
845848
float obin = (Ori[k] - ori)*bins_per_rad;
@@ -892,24 +895,23 @@ void calcSIFTDescriptor(
892895
// and scale the result, so that it can be easily converted
893896
// to byte array
894897
float nrm2 = 0;
895-
len = d*d*n;
896898
k = 0;
897899
#if (CV_SIMD || CV_SIMD_SCALABLE)
898900
{
899901
v_float32 __nrm2 = vx_setzero_f32();
900902
v_float32 __rawDst;
901-
for( ; k <= len - VTraits<v_float32>::vlanes(); k += VTraits<v_float32>::vlanes() )
903+
for( ; k <= len_ddn - VTraits<v_float32>::vlanes(); k += VTraits<v_float32>::vlanes() )
902904
{
903905
__rawDst = vx_load_aligned(rawDst + k);
904906
__nrm2 = v_fma(__rawDst, __rawDst, __nrm2);
905907
}
906908
nrm2 = (float)v_reduce_sum(__nrm2);
907909
}
908910
#endif
909-
for( ; k < len; k++ )
911+
for( ; k < len_ddn; k++ )
910912
nrm2 += rawDst[k]*rawDst[k];
911913

912-
float thr = std::sqrt(nrm2)*SIFT_DESCR_MAG_THR;
914+
const float thr = std::sqrt(nrm2)*SIFT_DESCR_MAG_THR;
913915

914916
i = 0, nrm2 = 0;
915917
#if 0 //CV_AVX2
@@ -920,7 +922,7 @@ void calcSIFTDescriptor(
920922
__m256 __dst;
921923
__m256 __nrm2 = _mm256_setzero_ps();
922924
__m256 __thr = _mm256_set1_ps(thr);
923-
for( ; i <= len - 8; i += 8 )
925+
for( ; i <= len_ddn - 8; i += 8 )
924926
{
925927
__dst = _mm256_loadu_ps(&rawDst[i]);
926928
__dst = _mm256_min_ps(__dst, __thr);
@@ -936,7 +938,7 @@ void calcSIFTDescriptor(
936938
nrm2_buf[4] + nrm2_buf[5] + nrm2_buf[6] + nrm2_buf[7];
937939
}
938940
#endif
939-
for( ; i < len; i++ )
941+
for( ; i < len_ddn; i++ )
940942
{
941943
float val = std::min(rawDst[i], thr);
942944
rawDst[i] = val;
@@ -954,7 +956,7 @@ if( dstMat.type() == CV_32F )
954956
v_float32 __min = vx_setzero_f32();
955957
v_float32 __max = vx_setall_f32(255.0f); // max of uchar
956958
v_float32 __nrm2 = vx_setall_f32(nrm2);
957-
for( k = 0; k <= len - VTraits<v_float32>::vlanes(); k += VTraits<v_float32>::vlanes() )
959+
for( k = 0; k <= len_ddn - VTraits<v_float32>::vlanes(); k += VTraits<v_float32>::vlanes() )
958960
{
959961
__dst = vx_load_aligned(rawDst + k);
960962
__dst = v_min(v_max(v_cvt_f32(v_round(v_mul(__dst, __nrm2))), __min), __max);
@@ -965,7 +967,7 @@ if( dstMat.type() == CV_32F )
965967
#pragma GCC diagnostic push
966968
#pragma GCC diagnostic ignored "-Waggressive-loop-optimizations" // iteration XX invokes undefined behavior
967969
#endif
968-
for( ; k < len; k++ )
970+
for( ; k < len_ddn; k++ )
969971
{
970972
dst[k] = saturate_cast<uchar>(rawDst[k]*nrm2);
971973
}
@@ -980,7 +982,7 @@ else // CV_8U
980982
v_float32 __dst0, __dst1;
981983
v_uint16 __pack01;
982984
v_float32 __nrm2 = vx_setall_f32(nrm2);
983-
for( k = 0; k <= len - VTraits<v_float32>::vlanes() * 2; k += VTraits<v_float32>::vlanes() * 2 )
985+
for( k = 0; k <= len_ddn - VTraits<v_float32>::vlanes() * 2; k += VTraits<v_float32>::vlanes() * 2 )
984986
{
985987
__dst0 = vx_load_aligned(rawDst + k);
986988
__dst1 = vx_load_aligned(rawDst + k + VTraits<v_float32>::vlanes());
@@ -994,7 +996,7 @@ else // CV_8U
994996
#pragma GCC diagnostic push
995997
#pragma GCC diagnostic ignored "-Waggressive-loop-optimizations" // iteration XX invokes undefined behavior
996998
#endif
997-
for( ; k < len; k++ )
999+
for( ; k < len_ddn; k++ )
9981000
{
9991001
dst[k] = saturate_cast<uchar>(rawDst[k]*nrm2);
10001002
}
@@ -1004,7 +1006,7 @@ else // CV_8U
10041006
}
10051007
#else
10061008
float nrm1 = 0;
1007-
for( k = 0; k < len; k++ )
1009+
for( k = 0; k < len_ddn; k++ )
10081010
{
10091011
rawDst[k] *= nrm2;
10101012
nrm1 += rawDst[k];
@@ -1013,15 +1015,15 @@ else // CV_8U
10131015
if( dstMat.type() == CV_32F )
10141016
{
10151017
float *dst = dstMat.ptr<float>(row);
1016-
for( k = 0; k < len; k++ )
1018+
for( k = 0; k < len_ddn; k++ )
10171019
{
10181020
dst[k] = std::sqrt(rawDst[k] * nrm1);
10191021
}
10201022
}
10211023
else // CV_8U
10221024
{
10231025
uint8_t *dst = dstMat.ptr<uint8_t>(row);
1024-
for( k = 0; k < len; k++ )
1026+
for( k = 0; k < len_ddn; k++ )
10251027
{
10261028
dst[k] = saturate_cast<uchar>(std::sqrt(rawDst[k] * nrm1)*SIFT_INT_DESCR_FCTR);
10271029
}

modules/features2d/test/test_sift.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,17 @@ TEST(Features2d_SIFT, descriptor_type)
3030
ASSERT_EQ(countNonZero(diff), 0) << "descriptors are not identical";
3131
}
3232

33+
TEST(Features2d_SIFT, regression_26139)
34+
{
35+
auto extractor = cv::SIFT::create();
36+
cv::Mat1b image{cv::Size{300, 300}, 0};
37+
std::vector<cv::KeyPoint> kps {
38+
cv::KeyPoint(154.076813f, 136.160904f, 111.078636f, 216.195618f, 0.00000899323549f, 7)
39+
};
40+
cv::Mat descriptors;
41+
extractor->compute(image, kps, descriptors); // we expect no memory corruption
42+
ASSERT_EQ(descriptors.size(), Size(128, 1));
43+
}
44+
3345

3446
}} // namespace

0 commit comments

Comments
 (0)