opencv icon indicating copy to clipboard operation
opencv copied to clipboard

Add alignment checks to Mat, silence cast alignment warnings

Open TomaszTB opened this issue 1 year ago • 2 comments

Working towards solving issue "Cast with incorrect alignment" https://github.com/opencv/opencv/issues/24265.

This PR adds alignment checks (DbgAssert) for accessing data in Mat, and silences alignment warnings (from -Wcast-align=strict) using an intermediate cast to void*.

A few tests break due to these changes (such as Core_Transform tests), as they fail the alignment checks. Not sure how to resolve this issue.

Example code for behavior of proposed changes:

#include <opencv2/opencv.hpp>
#include <iostream>

int main()
{
    std::cout << "Alignment of <uchar>:  " << alignof(uchar) << std::endl;
    std::cout << "Alignment of <double>: " << alignof(double) << std::endl;

    int cols = 6;
    int rows = 4;

    // Create 64F Mat
    cv::Mat mat64F(rows, cols, CV_64F);
    for (int row = 0; row < rows; ++row)
        for (int col = 0; col < cols; ++col)
            mat64F.at<double>(row, col) = row + col;

    // Access using double works (same size as 64F)
    std::cout << "This works: " << *mat64F.ptr<double>(0, 0) << std::endl;
    std::cout << "This works: " << *mat64F.ptr<double>(1, 1) << std::endl;
    // Access using uchar works (smaller than 64F)
    std::cout << "This works: " << 'a' + *mat64F.ptr<uchar>(0, 0) << std::endl;
    std::cout << "This works: " << 'a' + *mat64F.ptr<uchar>(1, 1) << std::endl;

    // Create 8U Mat
    cv::Mat mat8U(rows, cols, CV_8U);
    for (int row = 0; row < rows; ++row)
        for (int col = 0; col < cols; ++col)
            mat8U.at<uchar>(row, col) = 'a' + row + col;

    // Access using uchar works (same size as 8U)
    std::cout << "This works: " << *mat8U.ptr<uchar>(0, 0) << std::endl;
    std::cout << "This works: " << *mat8U.ptr<uchar>(1, 1) << std::endl;
    // Access using double works when the address is aligned to alignof(double)
    std::cout << "This works? " << *mat8U.ptr<double>(0, 0) << std::endl;
    // Access using double does NOT work when the address is not aligned to alignof(double)
    std::cout << "This don't:\n" << *mat8U.ptr<double>(1, 1) << std::endl;

    return 0;
}

Output of example code:

Alignment of <uchar>:  1
Alignment of <double>: 8
This works: 0
This works: 2
This works: 97
This works: 97
This works: a
This works: c
This works? 5.55527e+170
This don't:
OpenCV(4.10.0-dev) Error: Assertion failed (((uintptr_t)p & (alignof(_Tp) - 1)) == 0) in ptr, file /my/path/opencv4/opencv2/core/mat.inl.hpp, line 759
terminate called after throwing an instance of 'cv::Exception'
  what():  OpenCV(4.10.0-dev) /my/path/opencv4/opencv2/core/mat.inl.hpp:759: error: (-215:Assertion failed) ((uintptr_t)p & (alignof(_Tp) - 1)) == 0 in function 'ptr'

zsh: IOT instruction (core dumped)  ./opencv-test-build/opencv-test

Pull Request Readiness Checklist

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

  • [x] I agree to contribute to the project under Apache 2 License.
  • [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
  • [x] The PR is proposed to the proper branch
  • [x] There is a reference to the 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

TomaszTB avatar Jul 29 '24 00:07 TomaszTB

There are some troubles with contrib modules:

[1550/3258] Building CXX object modules/rgbd/CMakeFiles/opencv_rgbd.dir/src/depth_registration.cpp.o
FAILED: modules/rgbd/CMakeFiles/opencv_rgbd.dir/src/depth_registration.cpp.o 
/usr/bin/ccache /usr/bin/c++  -DCVAPI_EXPORTS -D_USE_MATH_DEFINES -D__OPENCV_BUILD=1 -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -I/home/ci/opencv_contrib/modules/rgbd/include -Imodules/rgbd -I/home/ci/opencv/modules/core/include -I/home/ci/opencv/modules/flann/include -I/home/ci/opencv/modules/imgproc/include -I/home/ci/opencv_contrib/modules/viz/include -I/home/ci/opencv/modules/features2d/include -I/home/ci/opencv/modules/calib3d/include -isystem . -isystem /usr/include/eigen3 -fsigned-char -W -Wall -Wreturn-type -Wnon-virtual-dtor -Waddress -Wsequence-point -Wformat -Wformat-security -Wmissing-declarations -Wundef -Winit-self -Wpointer-arith -Wshadow -Wsign-promo -Wuninitialized -Wsuggest-override -Wno-delete-non-virtual-dtor -Wno-comment -Wimplicit-fallthrough=3 -Wno-strict-overflow -fdiagnostics-show-option -pthread -fomit-frame-pointer -ffunction-sections -fdata-sections    -fvisibility=hidden -fvisibility-inlines-hidden -O3 -DNDEBUG  -DNDEBUG -fPIC   -std=c++11 -MD -MT modules/rgbd/CMakeFiles/opencv_rgbd.dir/src/depth_registration.cpp.o -MF modules/rgbd/CMakeFiles/opencv_rgbd.dir/src/depth_registration.cpp.o.d -o modules/rgbd/CMakeFiles/opencv_rgbd.dir/src/depth_registration.cpp.o -c /home/ci/opencv_contrib/modules/rgbd/src/depth_registration.cpp
In file included from /home/ci/opencv/modules/core/include/opencv2/core/mat.hpp:3795,
                 from /home/ci/opencv/modules/core/include/opencv2/core.hpp:58,
                 from /home/ci/opencv/modules/core/include/opencv2/core/utility.hpp:56,
                 from /home/ci/opencv_contrib/modules/rgbd/src/precomp.hpp:20,
                 from /home/ci/opencv_contrib/modules/rgbd/src/depth_registration.cpp:7:
/home/ci/opencv/modules/core/include/opencv2/core/mat.inl.hpp: In instantiation of 'const _Tp* cv::Mat_<_Tp>::operator[](int) const [with _Tp = short unsigned int]':
/home/ci/opencv_contrib/modules/rgbd/src/depth_registration.cpp:153:75:   required from 'void cv::rgbd::performRegistration(const cv::Mat_<_Tp>&, const Matx33f&, const Matx33f&, const cv::Mat_<float>&, const Matx44f&, cv::Size, bool, float, cv::Mat&) [with DepthDepth = short unsigned int; cv::Matx33f = cv::Matx<float, 3, 3>; cv::Matx44f = cv::Matx<float, 4, 4>; cv::Size = cv::Size_<int>]'
/home/ci/opencv_contrib/modules/rgbd/src/depth_registration.cpp:312:78:   required from here
/home/ci/opencv/modules/core/include/opencv2/core/mat.inl.hpp:1675:40: error: invalid conversion from 'const short unsigned int*' to 'short unsigned int*' [-fpermissive]
 1675 |     _Tp* p = (const _Tp*)((void*)(data + y*step.p[0]));
      |                                  ~~~~~~^~~~~~~~~~~~~~
      |                                        |
      |                                        const short unsigned int*
/home/ci/opencv/modules/core/include/opencv2/core/mat.inl.hpp: In instantiation of 'const _Tp* cv::Mat_<_Tp>::operator[](int) const [with _Tp = float]':
/home/ci/opencv_contrib/modules/rgbd/src/depth_registration.cpp:153:75:   required from 'void cv::rgbd::performRegistration(const cv::Mat_<_Tp>&, const Matx33f&, const Matx33f&, const cv::Mat_<float>&, const Matx44f&, cv::Size, bool, float, cv::Mat&) [with DepthDepth = float; cv::Matx33f = cv::Matx<float, 3, 3>; cv::Matx44f = cv::Matx<float, 4, 4>; cv::Size = cv::Size_<int>]'
/home/ci/opencv_contrib/modules/rgbd/src/depth_registration.cpp:320:68:   required from here

asmorkalov avatar Jul 29 '24 06:07 asmorkalov

Problems are visible on Debug builders only, e.g. here: http://pullrequest.opencv.org/buildbot/builders/precommit_linux64_no_opt/builds/109844

Need to investigate these cases.

opencv-alalek avatar May 16 '25 13:05 opencv-alalek