GetCPUDescriptorHandleForHeapStart stack corruption

只愿长相守 提交于 2020-01-12 14:58:51

问题


I've stumbled upon a rather unusual problem while programming with DirectX 12.0. No research so far has been insightful.

I am programming using C (not C++). It would appear the official DirectX 12 headers support bindings for both C and C++, however writing C equivalent code to do a said task causes a crash whereas C++ does not. I don't believe the error is mine.

Here's the details: I have here in my D3D12 device-initialisation procedure the following block of code:

/* Get a handle to the memory location in the render target
view heap to identify where the render target views will be
located for the two back buffers */
hRTV = pThis->pRTVHeap->lpVtbl->GetCPUDescriptorHandleForHeapStart(pThis->pRTVHeap);

Where hRTV stands for 'Handle to Render Target View' (D3D12_CPU_DESCRIPTOR_HANDLE) and pRTVHeap stands for 'Pointer to Render Target View Heap' (ID3D12DescriptorHeap).

Here is the C++ equivalent - this works fine:

/* Get a handle to the memory location in the render target
view heap to identify where the render target views will be
located for the two back buffers */
hRTV = this->pRTVHeap->GetCPUDescriptorHandleForHeapStart();

There are no compile-time errors present but at runtime, calling this method (GetCPUDescriptorHandleForHeapStart) in C triggers a stack corruption (%ESP is displaced by 4-bytes).

I examined the disassembly for the the method and made note of the RET (return) instruction:

mov         edi,edi
push        ebp
mov         ebp,esp
mov         ecx,dword ptr [ebp+8]
mov         eax,dword ptr [ecx+2Ch]
cmp         dword ptr [eax],2
jne         5029004A
mov         eax,dword ptr [ebp+0Ch]
mov         ecx,dword ptr [ecx+28h]
mov         dword ptr [eax],ecx
jmp         50290055
push        dword ptr [ebp+0Ch]
call        5029005E
mov         eax,dword ptr [ebp+0Ch]
pop         ebp
ret         8

For those familiar with assembly and (hopefully) the __stdcall calling convention of COM (Component Object Model) objects, the this (or equivalent) pointer, passed on the stack, is the first parameter (and, in this case, should be the only parameter) of the method, a practice that enables COM objects to access their own data.

The following code snippet (also shown above) is what elicits my confusion, and rightfully so when the runtime throws a 'misaligned stack pointer / stack corruption' (%ESP) error:

ret        8

Only one parameter should be passed in this case (this pointer). The size of a pointer (on a 32-bit system - my target architecture is x86) is 4 bytes (32 bits), so why does the callee clean up 8 bytes on the stack?

Am I right to call this a bug? Does Microsoft need to be informed of this issue? Am I wrong?

Thank you for your time and I hope anyone with more knowledge than I do can enlighten me. Please do not suggest the age-old argument of preferring C++ over C.


回答1:


SOLUTION

Debug symbols for D3D12.DLL reveal just enough. Naming conventions (e.g. ID3D12DescriptionHeap::GetCPUDescriptorHandleForHeapStart) are a strong indication that the DLL is written in C++. A (hidden) second parameter is indeed passed to the method - a pointer to the output structure D3D12_CPU_DESCRIPTOR_HANDLE (comprising nothing more than just an integer, aliased as a structure. I don't know why they do this). I forgot that C++ differs from C in that C++ can return structures as return values, and that structures cannot be passed as a return via the accumulator (%EAX) register, so it must be passed as a pointer on the stack to the callee.

The problem is bad C bindings (a Microsoft header bug). The following fix is proposed:

Old code:

D3D12_CPU_DESCRIPTOR_HANDLE (
    STDMETHODCALLTYPE *GetCPUDescriptorHandleForHeapStart )( 
    ID3D12DescriptorHeap * This);

Replace with:

void ( STDMETHODCALLTYPE *GetCPUDescriptorHandleForHeapStart )(
    ID3D12DescriptorHeap *This, D3D12_CPU_DESCRIPTOR_HANDLE *pOut);

Thank you.



来源:https://stackoverflow.com/questions/34118929/getcpudescriptorhandleforheapstart-stack-corruption

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!