Skip to content

Fix ORB integer overflow#20823

Merged
alalek merged 5 commits intoopencv:3.4from
AleksandrPanov:fix_orb_integer_overflow
Oct 7, 2021
Merged

Fix ORB integer overflow#20823
alalek merged 5 commits intoopencv:3.4from
AleksandrPanov:fix_orb_integer_overflow

Conversation

@AleksandrPanov
Copy link
Copy Markdown
Contributor

@AleksandrPanov AleksandrPanov commented Oct 6, 2021

Fixes opencv/opencv-python#537 "segmentation fault using ORB"

  • Problem in HarrisResponses(const Mat& img, const std::vector& layerinfo, std::vector& pts, int blockSize, float harris_k) from orb.cpp
  • An integer overflow has occurred in this line:
    const uchar* ptr0 = ptr00 + (y0 - r + layerinfo[z].y)*step + x0 - r + layerinfo[z].x;
  • To fix this problem, integer variable step was declared as size_t.
  • Also I ran performance tests: PERF_TEST_P(feature2d, detectAndExtract, testing::Combine(testing::Values(DETECTORS_EXTRACTORS), TEST_IMAGES))
    And the performance remained almost unchanged:
    test_new_version.txt
    test_old_version.txt

Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

  • I agree to contribute to the project under Apache 2 License.
  • To the best of my knowledge, the proposed patch is not based on a code under GPL or other license that is incompatible with OpenCV
  • The PR is proposed to proper branch
  • There is reference to original bug report and related work
  • There is accuracy test, performance test and test data in opencv_extra repository, if applicable
    Patch to opencv_extra has the same branch name.
  • The feature is well documented and sample code can be built with the project CMake

@AleksandrPanov AleksandrPanov changed the title Fix orb integer overflow Fix ORB integer overflow Oct 6, 2021
Copy link
Copy Markdown
Member

@alalek alalek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!


const uchar* ptr00 = img.ptr<uchar>();
int step = (int)(img.step/img.elemSize1());
size_t step = img.step/img.elemSize1();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, This would not help for 32-bit builds (sizeof(size_t) == 4).
We don't really want to support them (due to limited of available memory for such configuration).
So could you please to add CV_Check to catch overflow case below.

Copy link
Copy Markdown
Contributor Author

@AleksandrPanov AleksandrPanov Oct 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

integer overflow happens here:
const uchar* ptr0 = ptr00 + (y0 - r + layerinfo[z].y)*step + x0 - r + layerinfo[z].x;

ptr00 is pointer to begin image, (y0 - r + layerinfo[z].y)*step + x0 - r + layerinfo[z].x is offset, and offset is less then image size.

Сan 32 bit systems create a image larger than max(size_t)?
// sizeof(size_t) == 4 byte, image has one CV_8U channel

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a 32-bit system cannot create the image larger than max(size_t), then the offset will not overflow.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, probably it would fail earlier on image creation.

Comment on lines +146 to +148
applyTestTag(CV_TEST_TAG_LONG);
applyTestTag(CV_TEST_TAG_DEBUG_VERYLONG);
applyTestTag(CV_TEST_TAG_MEMORY_6GB);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apply tags in one call.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thx, fixed

Comment on lines +160 to +161
point1 = {border + i * 100, border + i * 100};
point2 = {width - border - i * 100, height - border * i * 100};
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

C++98 doesn't support initializer list. Use ctors:

Point point1(border + i * 100, border + i * 100);
Point point2(width - border - i * 100, height - border * i * 100);

Use Point instead of cv::Vec2i

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thx, fixed

Comment on lines +152 to +154
Ptr<ORB> orbPtr = ORB::create(31);
std::vector<KeyPoint> kps;
Mat fv;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Declare variable where are they used (this significantly increases code readability).
Right before detectAndCompute() call.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thx, fixed

@AleksandrPanov AleksandrPanov force-pushed the fix_orb_integer_overflow branch from a7ac94d to d7fbeb8 Compare October 7, 2021 10:03
@alalek
Copy link
Copy Markdown
Member

alalek commented Oct 7, 2021

Please eliminate Windows warnings.

@AleksandrPanov AleksandrPanov self-assigned this Oct 7, 2021
@AleksandrPanov
Copy link
Copy Markdown
Contributor Author

AleksandrPanov commented Oct 7, 2021

Please eliminate Windows warnings.

There is problem in this lines:

int Ix = (ptr[1] - ptr[-1])*2 + (ptr[-step+1] - ptr[-step-1]) + (ptr[step+1] - ptr[step-1]);
int Iy = (ptr[step] - ptr[-step])*2 + (ptr[step-1] - ptr[-step-1]) + (ptr[step+1] - ptr[-step+1]);

size_t_step and offset added to fix this problem:

size_t offset = (y0 - r + layerinfo[z].y)*size_t_step + (x0 - r + layerinfo[z].x);
const uchar* ptr0 = ptr00 + offset;

step was defined as int again (added CV_Check to prevent overflow).

const uchar* ptr00 = img.ptr<uchar>();
int step = (int)(img.step/img.elemSize1());
size_t size_t_step = img.step/img.elemSize1();
CV_Check(size_t_step, size_t_step <= INT_MAX, "step in img > INT_MAX");
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check doesn't prevent overflow below with step+1 expressions.

BTW, UBSAN can detect these overflows, but it dislikes negative indexing.

Copy link
Copy Markdown
Contributor Author

@AleksandrPanov AleksandrPanov Oct 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thx, fixed:
CV_Check(size_t_step, size_t_step + 1 <= INT_MAX, "step in img > INT_MAX");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One more step usage is in ofs calculation.

BTW, step in test case is 25072

I will add commit with checks.

@AleksandrPanov AleksandrPanov force-pushed the fix_orb_integer_overflow branch from c2b34c0 to e79c128 Compare October 7, 2021 15:53
@AleksandrPanov AleksandrPanov force-pushed the fix_orb_integer_overflow branch from e79c128 to ee98a00 Compare October 7, 2021 15:54
Copy link
Copy Markdown
Member

@alalek alalek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you 👍

@alalek alalek merged commit dfc94c5 into opencv:3.4 Oct 7, 2021
@alalek alalek mentioned this pull request Oct 8, 2021
@alalek alalek mentioned this pull request Oct 15, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants