Skip to content

Trivially copyable types breaking ABI compatiblity #20878

@DDoSolitary

Description

@DDoSolitary
System information (version)
  • OpenCV => 4.5.4
  • Operating System / Platform => Arch Linux
  • Compiler => GCC 11.1.0
Detailed description

eab2b9d made a few small classes trivially copyable. However, it changes how theses types are passed as function arguments, thus breaking binary compatibility and causing crashes of code built against earlier versions of opencv headers.

Steps to reproduce
#include <opencv2/core.hpp>

void foo() {
	cv::Size size(1, 2);
	cv::Mat mat(size, 3);
}

Just compile the above code against opencv 4.5.3 and 4.5.4 and check disassembler output.

g++ -c -o foo.o foo.cpp -I /usr/include/opencv4
objdump --demangle -rd foo.o

opencv 4.5.3

0000000000000000 <foo()>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   48 83 c4 80             add    $0xffffffffffffff80,%rsp
   8:   64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
   f:   00 00
  11:   48 89 45 f8             mov    %rax,-0x8(%rbp)
  15:   31 c0                   xor    %eax,%eax
  17:   48 8d 45 80             lea    -0x80(%rbp),%rax
  1b:   ba 02 00 00 00          mov    $0x2,%edx
  20:   be 01 00 00 00          mov    $0x1,%esi
  25:   48 89 c7                mov    %rax,%rdi
  28:   e8 00 00 00 00          call   2d <foo()+0x2d>
                        29: R_X86_64_PLT32      cv::Size_<int>::Size_(int, int)-0x4
  2d:   48 8d 55 80             lea    -0x80(%rbp),%rdx
  31:   48 8d 45 88             lea    -0x78(%rbp),%rax
  35:   48 89 d6                mov    %rdx,%rsi
  38:   48 89 c7                mov    %rax,%rdi
  3b:   e8 00 00 00 00          call   40 <foo()+0x40>
                        3c: R_X86_64_PLT32      cv::Size_<int>::Size_(cv::Size_<int> const&)-0x4
  40:   48 8d 4d 88             lea    -0x78(%rbp),%rcx
  44:   48 8d 45 90             lea    -0x70(%rbp),%rax
  48:   ba 03 00 00 00          mov    $0x3,%edx
  4d:   48 89 ce                mov    %rcx,%rsi
  50:   48 89 c7                mov    %rax,%rdi
  53:   e8 00 00 00 00          call   58 <foo()+0x58>
                        54: R_X86_64_PLT32      cv::Mat::Mat(cv::Size_<int>, int)-0x4
  58:   48 8d 45 90             lea    -0x70(%rbp),%rax
  5c:   48 89 c7                mov    %rax,%rdi
  5f:   e8 00 00 00 00          call   64 <foo()+0x64>
                        60: R_X86_64_PLT32      cv::Mat::~Mat()-0x4
  64:   48 8b 45 f8             mov    -0x8(%rbp),%rax
  68:   64 48 2b 04 25 28 00    sub    %fs:0x28,%rax
  6f:   00 00
  71:   74 05                   je     78 <foo()+0x78>
  73:   e8 00 00 00 00          call   78 <foo()+0x78>
                        74: R_X86_64_PLT32      __stack_chk_fail-0x4
  78:   c9                      leave
  79:   c3                      ret

After calling copy constructor of Size_, address of the object is taken (lea -0x78(%rbp),%rcx) and passed to constructor of Mat (mov %rcx,%rsi).

opencv 4.5.4

0000000000000000 <foo()>:
   0:   55                      push   %rbp
   1:   48 89 e5                mov    %rsp,%rbp
   4:   48 83 c4 80             add    $0xffffffffffffff80,%rsp
   8:   64 48 8b 04 25 28 00    mov    %fs:0x28,%rax
   f:   00 00
  11:   48 89 45 f8             mov    %rax,-0x8(%rbp)
  15:   31 c0                   xor    %eax,%eax
  17:   48 8d 45 88             lea    -0x78(%rbp),%rax
  1b:   ba 02 00 00 00          mov    $0x2,%edx
  20:   be 01 00 00 00          mov    $0x1,%esi
  25:   48 89 c7                mov    %rax,%rdi
  28:   e8 00 00 00 00          call   2d <foo()+0x2d>
                        29: R_X86_64_PLT32      cv::Size_<int>::Size_(int, int)-0x4
  2d:   48 8b 4d 88             mov    -0x78(%rbp),%rcx
  31:   48 8d 45 90             lea    -0x70(%rbp),%rax
  35:   ba 03 00 00 00          mov    $0x3,%edx
  3a:   48 89 ce                mov    %rcx,%rsi
  3d:   48 89 c7                mov    %rax,%rdi
  40:   e8 00 00 00 00          call   45 <foo()+0x45>
                        41: R_X86_64_PLT32      cv::Mat::Mat(cv::Size_<int>, int)-0x4
  45:   48 8d 45 90             lea    -0x70(%rbp),%rax
  49:   48 89 c7                mov    %rax,%rdi
  4c:   e8 00 00 00 00          call   51 <foo()+0x51>
                        4d: R_X86_64_PLT32      cv::Mat::~Mat()-0x4
  51:   48 8b 45 f8             mov    -0x8(%rbp),%rax
  55:   64 48 2b 04 25 28 00    sub    %fs:0x28,%rax
  5c:   00 00
  5e:   74 05                   je     65 <foo()+0x65>
  60:   e8 00 00 00 00          call   65 <foo()+0x65>
                        61: R_X86_64_PLT32      __stack_chk_fail-0x4
  65:   c9                      leave
  66:   c3                      ret

After calling constructor of Size_, content of the object is copied mov -0x78(%rbp),%rcx (as two ints in the object just fits in a 64-bit register) and passed to constructor of Mat.

Issue submission checklist
  • I report the issue, it's not a question
  • I checked the problem with documentation, FAQ, open issues,
    forum.opencv.org, Stack Overflow, etc and have not found solution
  • I updated to latest OpenCV version and the issue is still there
  • There is reproducer code and related data files: videos, images, onnx, etc

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions