IDE: Visual Studio 2015
Version: 10.0.0.2255
Target: Island (Windows x64 32-bit binary)
Description:
Trying to make the cast from FARPROC
to Func<SomethingElse>
I asked about here I tried to pass through Any
since that’s the only thing that compiled, and anything is supposed to be castable to Any
as I understand.
I tried something like:
var hSilverDLL1 = LoadLibrary("SilverDLL1.dll")
var pFoo = GetProcAddress(hSilverDLL1, "_Foo@0");
var pFoo2 = pFoo as? Any
var pFoo3 = pFoo2 as? Func<Bool>
x = pFoo3()
Note that I’m using as?
rather than as!
. So even if the casts are supposed to fail because I’m doing something wrong, I’m supposed to get a nil
. What I’m getting is a crash due to access violation.
After returning from the cal to GetProcAddress
I see the following disassembly:
0093547c e8aea20400 call ConsoleApplication2!GetProcAddress (0097f72f)
00935481 8945f4 mov dword ptr [ebp-0Ch],eax ss:002b:005df6a8=00000000
00935484 85c0 test eax,eax
00935486 7412 je ConsoleApplication2!ConsoleApplication2.Program::WndProc+0xba (0093549a)
00935488 68c0ed8e00 push offset ConsoleApplication2!GC_uobjfreelist_ptr+0xe54 (008eedc0)
0093548d 50 push eax
0093548e e8fd160000 call ConsoleApplication2!RemObjects.Elements.System.WindowsException::.+0x50 (00936b90)
00935493 83c408 add esp,8
00935496 85c0 test eax,eax
00935498 7502 jne ConsoleApplication2!ConsoleApplication2.Program::WndProc+0xbc (0093549c)
0093549a 31c0 xor eax,eax
0093549c 8945f8 mov dword ptr [ebp-8],eax
0093549f 85c0 test eax,eax
009354a1 7412 je ConsoleApplication2!ConsoleApplication2.Program::WndProc+0xd5 (009354b5)
009354a3 6850dd9100 push offset ConsoleApplication2!_real+0xd8 (0091dd50)
009354a8 50 push eax
009354a9 e8e2160000 call ConsoleApplication2!RemObjects.Elements.System.WindowsException::.+0x50 (00936b90)
009354ae 83c408 add esp,8
009354b1 85c0 test eax,eax
009354b3 7502 jne ConsoleApplication2!ConsoleApplication2.Program::WndProc+0xd7 (009354b7)
009354b5 31c0 xor eax,eax
009354b7 8945e8 mov dword ptr [ebp-18h],eax
009354ba 8945ec mov dword ptr [ebp-14h],eax
009354bd 50 push eax
009354be e81d490300 call ConsoleApplication2!Swift::ms_t15_Swift_d_Bit$Extension15_get__debugDescriptionp7_$mapped_r_tb_Swift_d_Bit+0x1230 (00969de0)
009354c3 83c404 add esp,4
009354c6 8845ff mov byte ptr [ebp-1],al
009354c9 f6d0 not al
009354cb a801 test al,1
009354cd 740d je ConsoleApplication2!ConsoleApplication2.Program::WndProc+0xfc (009354dc)
GetProcAddress
returned the correct address and after stepping through the mov on address 0x00935481 I see that the pFoo
holds the correct value:
0:000> gu
eax=62e7b470 ebx=00000000 ecx=5e52e37a edx=00000002 esi=002904fe edi=009353e0
eip=00935481 esp=005df69c ebp=005df6b4 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
ConsoleApplication2!ConsoleApplication2.Program::WndProc+0xa1:
00935481 8945f4 mov dword ptr [ebp-0Ch],eax ss:002b:005df6a8=00000000
0:000> r eax
eax=62e7b470
0:000> ln @eax
[longpath\program.swift @ 16] (62e7b470) SilverDLL1!SilverDLL1.<Global>::fgdgdf | (62e7b4c0) SilverDLL1!SilverDLL1.<Global>::bar123
Exact matches:
SilverDLL1!SilverDLL1.<Global>::fgdgdf (void)
0:000> t
eax=62e7b470 ebx=00000000 ecx=5e52e37a edx=00000002 esi=002904fe edi=009353e0
eip=00935484 esp=005df69c ebp=005df6b4 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
ConsoleApplication2!ConsoleApplication2.Program::WndProc+0xa4:
00935484 85c0 test eax,eax
0:000> dv /v
005df6bc hWnd = 0x002904fe
005df6c0 message = 0x111
005df6c4 wParam = 0
005df6c8 lParam = 0n2427230
005df6b3 x = true
005df6a4 hSilverDLL1 = 0x62e10000
005df6a8 pFoo = 0x62e7b470
005df6ac pFoo2 = 0x00000000
005df6a0 pFoo3 = 0x0025095e
ConsoleApplication2!GC_uobjfreelist_ptr+0xe54
seems to be a description of what kind of cast to perform (maybe some sort of type object). The multiple test eax, eax
s are the check for nil. ConsoleApplication2!RemObjects.Elements.System.WindowsException::.+0x50
seems the cast function.
We call the cast function. Test eax after it. If it’s not null we store it in [ebp-8] which we know is pFoo2.
0:000> ? ebp-8
Evaluate expression: 6157996 = 005df6ac
If we didn’t fail we call the cast function again, this time with ConsoleApplication2!_real+0xd8
. If we succeed we store the result of this cast in pFoo3 (and in [ebp-18] which I don’t recognize).
The we are somehow supposed to make the call through the thing on 0x009354be.
But I don;'t get there.
Stepping till the first call to the cast results in:
0:000> p
(2728.dcc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=c16af957 ebx=008eedc0 ecx=62e7b470 edx=89744371 esi=79077a48 edi=83e58955
eip=00936bd4 esp=005df678 ebp=005df68c iopl=0 nv up ei ng nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010286
ConsoleApplication2!RemObjects.Elements.System.WindowsException::.+0x94:
00936bd4 8b4710 mov eax,dword ptr [edi+10h] ds:002b:83e58965=????????
(There’s no handler. It becomes a second-chance exception and if not handled crashed the program.)
I have no idea what I did wrong, but even if the cast was bad I think I’m supposed to get a nil, not an AV and a crash. Swift ain’t Rust, but it’s supposed to be safe enough with a flow like this as far as I understand.
Expected Behavior: Get nil as a result of a cast.
Actual Behavior: Crash.
Bonus:
If I skip the calls in the debugger as if they succeeded I get another crash inside ConsoleApplication2!Swift::ms_t15_Swift_d_Bit$Extension15_get__debugDescriptionp7_$mapped_r_tb_Swift_d_Bit+0x1230
.