Thu Mar 28 15:58:57 2013: Request 84268 was acted upon.
Transaction: Correspondence added by BULKDD
       Queue: Win32-API
     Subject: Win32::API: Bug/Exception in call_asm_x86_msvc.asm
   Broken in: (no value)
    Severity: (no value)
       Owner: Nobody
  Requestors: rkeuc...@allgeier.com
      Status: new
 Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=84268 >


On Thu Mar 28 13:42:02 2013, rkeuc...@allgeier.com wrote:
> I get an exception in call_asm_x86_msvc.asm, raised at bad_esp.
> ESP
>    and EBP do not match.

Your prototype is wrong. Either the func in the DLL is actually __cdecl because 
it doesn't explicitly say __stdcall or WINAPI in each declaration and wasn't 
compiled with -Gz and the default in Win32::API is always __stdcall unless 
specified otherwise (this is the opposite of Visual C and GCC's defaults), or 
it is a __stdcall which takes a different amount of args than you specified in 
the prototype string.

> 
> Using the C version works. Why is the ASM-
>    Version the default for MSVC?
> 

The inline assembly version was very inefficient compared to the ideal design, 
the inline assembly version copied the same data between memory and register 
2-4 times redundantly before writing it to memory for the final time, also the 
call instruction appears 3 different times (but called only once) in the inline 
assembly version instead of once. The C version (still used with GCC) doesn't 
compare ESP to EBP to find wrong prototypes yet (not sure if the C version ever 
will).

> I compiled a fresh perl for
>    testing and debugging this.
> The called DLL is also built with MSVC
>    16 and uses WINAPI calling convention.

Are you sure?

> 
> The signature is:
>    Win32::API->Import("svapi32_vc100.dll",  'ULONG
>    svapi_connect(LPVOID hsv,LPSTR s1,LPSTR s2,LPSTR s3,LPSTR s4,LPSTR
>    s5,LPSTR s6,LPSTR s7,LPSTR s8,LPSTR s9, LPSTR s10)');


The above is probably a __cdecl in the DLL since __stdcall isn't specified 
anywhere and -Gr and -Gz weren't used (-Gd wasn't used either, but it is on by 
default). I made a test function below to try your prototype.
_______________________________________________

API_TEST_API ULONG svapi_connect(LPVOID hsv,LPSTR s1,LPSTR s2,LPSTR s3,
        LPSTR s4,LPSTR s5,LPSTR s6,LPSTR s7,LPSTR s8,LPSTR s9, LPSTR s10) {
    if(hsv == 0x0
       && atoi(s1) == 1
       && atoi(s2) == 2
       && atoi(s3) == 3
       && atoi(s4) == 4
       && atoi(s5) == 5
       && atoi(s6) == 6
       && atoi(s7) == 7
       && atoi(s8) == 8
       && atoi(s9) == 9
       && atoi(s10) == 10)
        return 2;
    else{
        DebugBreak();
        return 0;
    }
}
___________________________________________________
this is fine, notice I changed the 1st parameter from LPVOID to ULONG (LPVOID 
is a char * in Win32::API, not an opaque pointer as normally thought of LPVOID)
_______________________________________________
use Win32::API;
    Win32::API->Import("api_test.dll",  'ULONG __cdecl svapi_connect(ULONG '
.'hsv,LPSTR s1,LPSTR s2,LPSTR s3,LPSTR s4,LPSTR s5,LPSTR s6,LPSTR s7,LPSTR s8,'
.'LPSTR s9, LPSTR s10)');
    
die "bad return" if svapi_connect(0..10) != 2;
_______________________________________________


This causes "Unhandled exception at 0x7c812afb in perl.exe: 0xC0000028: An 
invalid or unaligned stack was encountered during an unwind operation." with 
0.76_01. 
_______________________________________________
use Win32::API;
    Win32::API->Import("api_test.dll",  'ULONG svapi_connect(ULONG '
.'hsv,LPSTR s1,LPSTR s2,LPSTR s3,LPSTR s4,LPSTR s5,LPSTR s6,LPSTR s7,LPSTR s8,'
.'LPSTR s9, LPSTR s10)');
    
die "bad return" if svapi_connect(0..10) != 2;
_______________________________________________

I plan to change the RaiseException to a Perl catchable croak based on the 
opinions in http://perlmonks.org/?node_id=1024423 in a future  0.76_02. Also I 
might switch the RaiseException to a DebugBreak since RaiseException uses alot 
of C autos and changes esp/ebp alot (but ebp sort of points to the incoming 
args to RaiseException from Call_asm). Do you have another opinion of what to 
do when there is a prototype mistake?

Reply via email to