Why is the wrong calling convention sometimes used?

I used the "StartServiceCtrlDispatcher" function to register a callback function (called ServiceMain) on Windows, but the callback function that I declared was compiled with the wrong calling convention.

The fact is that on some computers , when the application returned from the callback function, the application crashed, but on other computers the application did not crash .. p>

Now that I found the error, everything worked, but I just don’t understand why on some computers it worked correctly without failures?

Thanks!: -)

+4
source share
4 answers

This is all very specific to Windows, we are not talking about standard C ++ here.

Documentation Check StartServiceDispatcher has only one argument and is declared as a WINAPI , which in turn means __stcall calling convention.

For stand-alone functions, __stdcall is one of two main calling conventions. The other is __cdecl . The difference in machine code levels is simply the one who restores the stack pointer: with __stdcall it is the function itself, and with __cdecl it is the call code.

When a function is actually __stdcall , but called as if it were __cdecl , the situation is that there are two attempts to restore the stack pointer: one at the exit of the function and one in the calling code, The function in the function will succeed. Depending on how you try to call the code, it can completely ruin things (for example, simply adding the required offset, treating the stack pointer as relative) or it may not have a harmful effect. But this most likely creates a mess, since the assumption about the value of the stack pointer when returning from the function is incorrect.

When the function is actually __cdecl , it will not restore the stack pointer itself, since this is the responsibility of the call code. And if the calling code treats it as __stdcall , then the calling code will not restore it, since the function does this from the presentation of the calling code. As a result, if you did not receive an early failure (due to broken assumptions), then you should repeat that repeated calls, say, in a loop, will contain stack space.

All this is very important. Undefined Behavior.

And one property of Undefined Behavior is that it can do anything, including, apparently, the work of & hellip;

Cheers and hth.,

+5
source

Call conventions vary in detail, for example, which registers are stored. If you were not able to save anything that you still need in these registers, then it did not matter that they were erased when they did not need it. Likewise, if your calling convention is different from how it relates to return values, if you don't return anything, then that doesn't matter.

Fortunately, x64 has only one calling convention, and all this mess will be in the past.

+2
source

Computers that failed the application may have used the .NET Framework version 4.

Take a look at the following article: http://msdn.microsoft.com/en-us/library/ee941656.aspx

The section "Interoperability" states:

"To improve performance when interacting with unmanaged code, incorrect calling conventions in the platform call now cause the application to crash. In previous versions, the marshaling level resolved these errors to the stack."

+1
source

All this is due to what is current in memory. Suppose you have two functions:

 void stdcall f1(...) { ... } void cdecl f2(...) { ... } 

stdcall is a Windows calling convention, while cdecl used by most compilers. The difference between the two is who is responsible for clearing the stack after the call. In stdcall caller ( f1 or f2 ) makes the caller in cdecl .

In the end, the stack is filled with unknown values. Therefore, when it is cleared (erroneously), the next value that you get on the stack is not defined. This may well be an acceptable value, or it can be very bad. This, in principle, is how the stack overflow works (error, not site).

0
source

All Articles