-
-
Notifications
You must be signed in to change notification settings - Fork 55.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
OpenCV 3.1 x64 -- Incorrect code is generated when calling cvGetSize from a x64 C library. #6221
Comments
Just realized I forgot to include an important piece of information: I've only seen this happening when building for x64 (which doesn't mean that it works for x86, just that I've only tested x64). I've updated the original issue with this information. |
…forms now work with the same OpenCV version (3.1.0) - Updated MSVC build script to clone the 3.1.0 branch. Also updated the cmake commandline (3.1.0 needs opencv_ml to be built as well) - Updated MSVC readme to use 3.1.0 - Updated osx build script to also clone 3.1.0 branch instead of whatever is currently at master - Due to a bug in OpenCV 3.1.0 it is not possible to call cvGetSize from C source files under MSVC (it will crash due to incorrect code generation). As a workaround for this (until the bug in OpenCV is fixed), the psmove_tracker.c file (which is the only code calling cvGetSize) is now force-compiled as C++. See opencv/opencv#6221 for more info. - In order to be able to build psmove_tracker.c as C++, some code needed to be updated (extern "C" added where relevant, tracker_default_settings can no longer be initialized using C-style designated initializer)
C API is not supported anymore and should not be used. Moreover some "C" calls can raise C++ exceptions. |
Lol. That is "a" response, I suppose. |
This is terrible. |
Please state the information for your system
In which part of the OpenCV library you got the issue?
Description
When using OpenCV 3.1 from a x64 C library, incorrect code is generated when calling
cvGetSize
. I have only seen this when compiling for x64 (I only have x64 projects), but I don't know whether the bug also appears when building for x86.The reason for this bug is the fact that the
CvSize
struct is defined as follows:Since OpenCV itself is compiled as C++ (not as C), this means that
CvSize
has constructors (#ifdef __cplusplus
== true), which makes it a user-defined type. This in turn leads the MSVC compiler to assume that functions returning this struct by value cannot return it in a register, which causes the following code to be generated forcvGetSize
(note: this is just the function prologue):Note that up until this point, everything is still correct.
cvGetSize
is a function taking two arguments: the address where the return value ofcvGetSize
should be stored is passed inrcx
, thearr
argument is passed inrdx
.However, when you try to call this function from a file compiled as C (not C++), things break down. This is because the constructors in
CvSize
dissapear (#ifdef __cplusplus
== false), which now leads the compiler to assume that the return value forcvGetSize
will be returned in a register (rax
) sincesizeof(CvSize)
== 8.So, when calling the function, only one parameter is pushed onto the stack (the
arr
argument), which mismatches with what the generated code forCvSize
internally expects. This leads to the following (incorrect) calling code:Note a few things here:
frame
is stored inrcx
, which is wherecvGetSize
expects to find the address where the return value should be stored.cvGetSize
to be stored inrax
, which will not be the caseAll of this means that
cvGetSize
will read its argument from the wrong address and either throw an error or crash.However, when you instead call this function from a file compiled as C++ (not C), correct code is generated:
As you can clearly see, 2 arguments are passed to the function; the address where the return value should be stored in
rcx
and thearr
argument to the function inrdx
. This matches with the internally generated code forcvGetSize
, so everything works as expected.I think the current code probably works fine on other compilers (I haven't tried), but that's more of an accident than an intended feature. I believe this is firmly in undefined behaviour territory, so really anything could happen; the code is incorrect.
To fix this, I think the constructors should be removed from
CvSize
. There are probably also other structs that may suffer from similar issues (at a glance,CvSize2D32f
,CvBox2D
all have a similar problem).Some links that might be useful:
https://msdn.microsoft.com/en-us/library/1e02627y.aspx
http://stackoverflow.com/questions/22901697/error-in-c-code-linkage-warning-c4190-type-has-c-linkage-specified-but-retu
Code example to reproduce the issue / Steps to reproduce the issue
Create (or reuse) a x64 Visual Studio project which is setup to include/link against OpenCV 3 x64
Create a
main.c
filePut the following code in there:
Right-click on main.c in Visual Studio and go to Properties -> C/C++ -> Advanced
Set the Compile As field to Compile as C code (/TC)
Put a breakpoint on the line calling
cvGetSize
and run the programMake note of the pointer value of
frame
Step into
cvGetSize
Notice that the argument (
arr
) is not the correct pointer value (ie. it is not pointing toframe
).Press F5 to continue running the code and note the error (
CV_Error( CV_StsBadArg, "Array should be CvMat or IplImage" );
)Now set the Compile As field of main.c to Compile as C++ code (/TP)
Run again
Notice that the argument to
cvGetSize
is now correct and no error is thrownThe text was updated successfully, but these errors were encountered: