gfx-rs / wgpu-native

Native WebGPU implementation based on wgpu-core
Apache License 2.0
850 stars 98 forks source link

wgpuAdapterGetLimits may lead to "Access violation reading location" if WGPUSupportedLimits is uninitialized #340

Closed laurelkeys closed 8 months ago

laurelkeys commented 8 months ago

Using wgpu_native.dll and .pdb (v0.18.1.4) from C++, I stumbled upon an "Access violation reading location 0xFFFFFFFFFFFFFFFF." when I first tried to use the wgpuAdapterGetLimits function.

Here's a minimal example that showcases the issue (I crash on the last line, when running from within Visual Studio 2022):

int main(int argc, char **argv)
{
    WGPUInstance instance = wgpuCreateInstance(nullptr);

    WGPUAdapter adapter = nullptr;
    const auto callback = 
        [](WGPURequestAdapterStatus status, WGPUAdapter adapter, char const *, void *userdata) {
            if (status == WGPURequestAdapterStatus_Success) {
                *reinterpret_cast<WGPUAdapter *>(userdata) = adapter;
            }
        };
    wgpuInstanceRequestAdapter(instance, nullptr, callback, static_cast<void *>(&adapter));

    WGPUSupportedLimits limits; // using `= {};` will lead it not to crash
    wgpuAdapterGetLimits(adapter, &limits);
}

From the call stack (see below), the problem seems to be in an unsafe block of write_limits_struct: https://github.com/gfx-rs/wgpu-native/blob/5b75378728c965e3be4d6d9c69b4516ebde4522d/src/conv.rs#L418-L434

Click to show the call stack and disassembly...
I get a "Exception thrown at 0x00007FF8F08CF58E (wgpu_native.dll) in minimal.exe: 0xC0000005: Access violation reading location 0xFFFFFFFFFFFFFFFF.", with the call stack: ``` wgpu_native.dll!wgpu_native::conv::write_limits_struct(wgpu_types::Limits wgt_limits, wgpu_native::native::WGPUSupportedLimits * supported_limits) wgpu_native.dll!wgpu_native::wgpuAdapterGetLimits(wgpu_native::WGPUAdapterImpl * adapter, enum2$>> limits) minimal.exe!main(int argc, char * * argv) ``` Looking at the disassembly of `wgpu_native::conv::write_limits_struct(wgpu_types::Limits, wgpu_native::native::WGPUSupportedLimits *)`, we have: ```assembly --- D:\a\wgpu-native\wgpu-native\src\conv.rs ----------------------------------- 00007FF8F08CF400 sub rsp,178h 00007FF8F08CF407 mov qword ptr [rsp+30h],rdx 00007FF8F08CF40C mov qword ptr [rsp+28h],rcx 00007FF8F08CF411 mov qword ptr [rsp+168h],rdx 00007FF8F08CF419 add rdx,8 00007FF8F08CF41D lea rcx,[rsp+38h] 00007FF8F08CF422 mov r8d,90h 00007FF8F08CF428 call memcpy (07FF8F122D321h) 00007FF8F08CF42D mov rcx,qword ptr [wgt_limits] 00007FF8F08CF432 mov eax,dword ptr [rcx] 00007FF8F08CF434 mov dword ptr [limits],eax 00007FF8F08CF438 mov eax,dword ptr [rcx+4] 00007FF8F08CF43B mov dword ptr [rsp+3Ch],eax 00007FF8F08CF43F mov eax,dword ptr [rcx+8] 00007FF8F08CF442 mov dword ptr [rsp+40h],eax 00007FF8F08CF446 mov eax,dword ptr [rcx+0Ch] 00007FF8F08CF449 mov dword ptr [rsp+44h],eax 00007FF8F08CF44D mov eax,dword ptr [rcx+10h] 00007FF8F08CF450 mov dword ptr [rsp+48h],eax 00007FF8F08CF454 mov eax,dword ptr [rcx+14h] 00007FF8F08CF457 mov dword ptr [rsp+50h],eax 00007FF8F08CF45B mov eax,dword ptr [rcx+18h] 00007FF8F08CF45E mov dword ptr [rsp+54h],eax 00007FF8F08CF462 mov eax,dword ptr [rcx+1Ch] 00007FF8F08CF465 mov dword ptr [rsp+58h],eax 00007FF8F08CF469 mov eax,dword ptr [rcx+20h] 00007FF8F08CF46C mov dword ptr [rsp+5Ch],eax 00007FF8F08CF470 mov eax,dword ptr [rcx+24h] 00007FF8F08CF473 mov dword ptr [rsp+60h],eax 00007FF8F08CF477 mov eax,dword ptr [rcx+28h] 00007FF8F08CF47A mov dword ptr [rsp+64h],eax 00007FF8F08CF47E mov eax,dword ptr [rcx+2Ch] 00007FF8F08CF481 mov dword ptr [rsp+68h],eax 00007FF8F08CF485 mov eax,dword ptr [rcx+30h] 00007FF8F08CF488 mov dword ptr [rsp+6Ch],eax 00007FF8F08CF48C mov eax,dword ptr [rcx+34h] 00007FF8F08CF48F mov qword ptr [rsp+70h],rax 00007FF8F08CF494 mov eax,dword ptr [rcx+38h] 00007FF8F08CF497 mov qword ptr [rsp+78h],rax 00007FF8F08CF49C mov eax,dword ptr [rcx+3Ch] 00007FF8F08CF49F mov dword ptr [rsp+88h],eax 00007FF8F08CF4A6 mov rax,qword ptr [rcx+40h] 00007FF8F08CF4AA mov qword ptr [rsp+90h],rax 00007FF8F08CF4B2 mov eax,dword ptr [rcx+48h] 00007FF8F08CF4B5 mov dword ptr [rsp+98h],eax 00007FF8F08CF4BC mov eax,dword ptr [rcx+4Ch] 00007FF8F08CF4BF mov dword ptr [rsp+9Ch],eax 00007FF8F08CF4C6 mov eax,dword ptr [rcx+50h] 00007FF8F08CF4C9 mov dword ptr [rsp+80h],eax 00007FF8F08CF4D0 mov eax,dword ptr [rcx+54h] 00007FF8F08CF4D3 mov dword ptr [rsp+84h],eax 00007FF8F08CF4DA mov eax,dword ptr [rcx+58h] 00007FF8F08CF4DD mov dword ptr [rsp+0A0h],eax 00007FF8F08CF4E4 mov eax,dword ptr [rcx+5Ch] 00007FF8F08CF4E7 mov dword ptr [rsp+0B0h],eax 00007FF8F08CF4EE mov eax,dword ptr [rcx+60h] 00007FF8F08CF4F1 mov dword ptr [rsp+0B4h],eax 00007FF8F08CF4F8 mov eax,dword ptr [rcx+64h] 00007FF8F08CF4FB mov dword ptr [rsp+0B8h],eax 00007FF8F08CF502 mov eax,dword ptr [rcx+68h] 00007FF8F08CF505 mov dword ptr [rsp+0BCh],eax 00007FF8F08CF50C mov eax,dword ptr [rcx+6Ch] 00007FF8F08CF50F mov dword ptr [rsp+0C0h],eax 00007FF8F08CF516 mov eax,dword ptr [rcx+70h] 00007FF8F08CF519 mov dword ptr [rsp+0C4h],eax 00007FF8F08CF520 lea rcx,[rsp+0C8h] 00007FF8F08CF528 lea rdx,[limits] 00007FF8F08CF52D mov r8d,90h 00007FF8F08CF533 call memcpy (07FF8F122D321h) 00007FF8F08CF538 mov rcx,qword ptr [rsp+30h] 00007FF8F08CF53D add rcx,8 00007FF8F08CF541 lea rdx,[rsp+0C8h] 00007FF8F08CF549 mov r8d,90h 00007FF8F08CF54F call memcpy (07FF8F122D321h) 00007FF8F08CF554 mov rdx,qword ptr [rsp+30h] 00007FF8F08CF559 mov rcx,qword ptr [rdx] 00007FF8F08CF55C call core::ptr::mut_ptr::impl$0::as_ref (07FF8F07EEAF0h) 00007FF8F08CF561 mov qword ptr [rsp+158h],rax 00007FF8F08CF569 mov rdx,qword ptr [rsp+158h] 00007FF8F08CF571 mov eax,1 00007FF8F08CF576 xor ecx,ecx 00007FF8F08CF578 cmp rdx,0 00007FF8F08CF57C cmove rax,rcx 00007FF8F08CF580 cmp rax,1 00007FF8F08CF584 jne wgpu_native::conv::write_limits_struct+197h (07FF8F08CF597h) 00007FF8F08CF586 mov rax,qword ptr [rsp+158h] => 00007FF8F08CF58E cmp dword ptr [rax+8],30005h 00007FF8F08CF595 je wgpu_native::conv::write_limits_struct+19Fh (07FF8F08CF59Fh) 00007FF8F08CF597 add rsp,178h 00007FF8F08CF59E ret 00007FF8F08CF59F mov rcx,qword ptr [wgt_limits] 00007FF8F08CF5A4 mov rax,qword ptr [rsp+30h] 00007FF8F08CF5A9 mov rax,qword ptr [rax] 00007FF8F08CF5AC mov qword ptr [rsp+20h],rax 00007FF8F08CF5B1 mov qword ptr [rsp+170h],rax 00007FF8F08CF5B9 mov edx,dword ptr [rcx+74h] 00007FF8F08CF5BC mov ecx,dword ptr [rcx+78h] 00007FF8F08CF5BF mov dword ptr [rsp+160h],edx 00007FF8F08CF5C6 mov dword ptr [rsp+164h],ecx 00007FF8F08CF5CD and rax,7 00007FF8F08CF5D1 cmp rax,0 00007FF8F08CF5D5 sete al 00007FF8F08CF5D8 test al,1 00007FF8F08CF5DA jne wgpu_native::conv::write_limits_struct+1DEh (07FF8F08CF5DEh) 00007FF8F08CF5DC jmp wgpu_native::conv::write_limits_struct+1F9h (07FF8F08CF5F9h) 00007FF8F08CF5DE mov rax,qword ptr [rsp+20h] 00007FF8F08CF5E3 mov edx,dword ptr [rsp+160h] 00007FF8F08CF5EA mov ecx,dword ptr [rsp+164h] 00007FF8F08CF5F1 mov dword ptr [rax+10h],edx 00007FF8F08CF5F4 mov dword ptr [rax+14h],ecx 00007FF8F08CF5F7 jmp wgpu_native::conv::write_limits_struct+197h (07FF8F08CF597h) 00007FF8F08CF5F9 mov rdx,qword ptr [rsp+20h] 00007FF8F08CF5FE lea r8,[impl$, core::error::Error>::vtable$+1400h (07FF8F123AD28h)] 00007FF8F08CF605 mov ecx,8 00007FF8F08CF60A call core::panicking::panic_misaligned_pointer_dereference (07FF8F122DDF0h) 00007FF8F08CF60F ud2 ``` I have pointed out the line it breaks execution at with a `=>` above.

Please let me know if there's more information I could provide.

cwfitzgerald commented 8 months ago

This is to be expected - you need to zero initialize the struct because of the presence of the pnext pointer. We need to walk the pnext chain to fill in extra limit structs that are in the chain. If you leave it uninitialized, and the pnext chain is not null, we try to walk it and fail.

laurelkeys commented 8 months ago

Oh, definitely! I guess I saw the std::mem::transmute and stopped there instead of reading 4 lines down to see it's actually dereferencing a .nextInChain. Thanks for the quick reply.