Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix ID2D1Device5/6 hook offsets #938

Merged
merged 1 commit into from May 31, 2023
Merged

Fix ID2D1Device5/6 hook offsets #938

merged 1 commit into from May 31, 2023

Conversation

lhecker
Copy link
Contributor

@lhecker lhecker commented May 30, 2023

ID2D1Device4 has two additional interface members: Set and
GetMaximumColorGlyphCacheMemory. These two were unaccounted for in
HookDevice, leading to crashes when any of these functions were called.

ID2D1Device4 has two additional interface members: Set and
GetMaximumColorGlyphCacheMemory. These two were unaccounted for in
HookDevice, leading to crashes when any of these functions were called.
MyDebug(L"ID2D1Device5 hooked");
}
CComPtr<ID2D1Device6> ptr7;
hr = (d2dDevice)->QueryInterface(&ptr7);
if SUCCEEDED(hr) {
HOOK(ptr7, CreateDeviceContext7, 18);
HOOK(ptr7, CreateDeviceContext7, 20);
Copy link
Contributor Author

@lhecker lhecker May 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have received a number of crash reports for Windows Terminal Preview 1.18 when MacType is being used. While debugging I found that this occurs whenever we call ID2D1Device4::SetMaximumColorGlyphCacheMemory.

I don't understand how MacType or even just how EasyHook works, but I noticed that the indices for these two members seem to be highly inconsistent with the others, when you list them up (copied out of the D2D headers and simplified):

MIDL_INTERFACE("00000000-0000-0000-C000-000000000046") IUnknown
{
    /*  0 */ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, _COM_Outptr_ void __RPC_FAR *__RPC_FAR *ppvObject) = 0;
    /*  1 */ virtual ULONG STDMETHODCALLTYPE AddRef( void) = 0;
    /*  2 */ virtual ULONG STDMETHODCALLTYPE Release( void) = 0;
};

interface DX_DECLARE_INTERFACE("2cd90691-12e2-11dc-9fed-001143a055f9") ID2D1Resource  : public IUnknown
{
    /*  3 */ STDMETHOD_(void, GetFactory)(_Outptr_ ID2D1Factory **factory) CONST PURE;
};

interface DX_DECLARE_INTERFACE("47dd575d-ac05-4cdd-8049-9b02cd16f44c") ID2D1Device  : public ID2D1Resource
{
    /*  4 */ STDMETHOD(CreateDeviceContext)(D2D1_DEVICE_CONTEXT_OPTIONS options, _COM_Outptr_ ID2D1DeviceContext **deviceContext) PURE;
    /*  5 */ STDMETHOD(CreatePrintControl)(_In_ IWICImagingFactory *wicFactory, _In_ IPrintDocumentPackageTarget *documentTarget, _In_opt_ CONST D2D1_PRINT_CONTROL_PROPERTIES *printControlProperties, _COM_Outptr_ ID2D1PrintControl **printControl) PURE;
    /*  6 */ STDMETHOD_(void, SetMaximumTextureMemory)(UINT64 maximumInBytes) PURE;
    /*  7 */ STDMETHOD_(UINT64, GetMaximumTextureMemory)() CONST PURE;
    /*  8 */ STDMETHOD_(void, ClearResources)(UINT32 millisecondsSinceUse = 0) PURE;
};

interface DX_DECLARE_INTERFACE("d21768e1-23a4-4823-a14b-7c3eba85d658") ID2D1Device1  : public ID2D1Device
{
    /*  9 */ STDMETHOD_(D2D1_RENDERING_PRIORITY, GetRenderingPriority)() PURE;
    /* 10 */ STDMETHOD_(void, SetRenderingPriority)(D2D1_RENDERING_PRIORITY renderingPriority) PURE;
    /* 11 */ STDMETHOD(CreateDeviceContext)(D2D1_DEVICE_CONTEXT_OPTIONS options, _COM_Outptr_ ID2D1DeviceContext1 **deviceContext1) PURE;
};

interface DX_DECLARE_INTERFACE("a44472e1-8dfb-4e60-8492-6e2861c9ca8b") ID2D1Device2  : public ID2D1Device1
{
    /* 12 */ STDMETHOD(CreateDeviceContext)(D2D1_DEVICE_CONTEXT_OPTIONS options, _COM_Outptr_ ID2D1DeviceContext2 **deviceContext2) PURE;
    /* 13 */ STDMETHOD_(void, FlushDeviceContexts)(_In_ ID2D1Bitmap *bitmap) PURE;
    /* 14 */ STDMETHOD(GetDxgiDevice)(_COM_Outptr_ IDXGIDevice **dxgiDevice) PURE;
};

interface DX_DECLARE_INTERFACE("852f2087-802c-4037-ab60-ff2e7ee6fc01") ID2D1Device3  : public ID2D1Device2
{
    /* 15 */ STDMETHOD(CreateDeviceContext)(D2D1_DEVICE_CONTEXT_OPTIONS options, _COM_Outptr_ ID2D1DeviceContext3 **deviceContext3) PURE;
};

interface DX_DECLARE_INTERFACE("d7bdb159-5683-4a46-bc9c-72dc720b858b") ID2D1Device4  : public ID2D1Device3
{
    /* 16 */ STDMETHOD(CreateDeviceContext)(D2D1_DEVICE_CONTEXT_OPTIONS options, _COM_Outptr_ ID2D1DeviceContext4 **deviceContext4) PURE;
    /* 17 */ STDMETHOD_(void, SetMaximumColorGlyphCacheMemory)(UINT64 maximumInBytes) PURE;
    /* 18 */ STDMETHOD_(UINT64, GetMaximumColorGlyphCacheMemory)() CONST PURE;
};

interface DX_DECLARE_INTERFACE("d55ba0a4-6405-4694-aef5-08ee1a4358b4") ID2D1Device5  : public ID2D1Device4
{
    /* 19 */ STDMETHOD(CreateDeviceContext)(D2D1_DEVICE_CONTEXT_OPTIONS options, _COM_Outptr_ ID2D1DeviceContext5 **deviceContext5) PURE;
};

interface DX_DECLARE_INTERFACE("7bfef914-2d75-4bad-be87-e18ddb077b6d") ID2D1Device6  : public ID2D1Device5
{
    /* 20 */ STDMETHOD(CreateDeviceContext)(D2D1_DEVICE_CONTEXT_OPTIONS options, _COM_Outptr_ ID2D1DeviceContext6 **deviceContext6) PURE;
};

I've not tested this change, but I'm still very confident about the correctness of this fix.

@snowie2000
Copy link
Owner

Basically, these indices are the index of the function pointers in their respective vtable.

We use easyhook to find the actual function and hijack it to our function. If the indice is wrong, then the wrong function will be intercepted, and the data could be corrupted.

@snowie2000 snowie2000 merged commit 0f5bd10 into snowie2000:directwrite May 31, 2023
@snowie2000
Copy link
Owner

Confirmed that vtbl index for ID2D1Device5/6 is incorrect because of the two functions introduced by ID2D1Device4.

@snowie2000
Copy link
Owner

Published as a preview release.

@lhecker lhecker deleted the device4-crash-fix branch May 31, 2023 08:11
@lhecker
Copy link
Contributor Author

lhecker commented May 31, 2023

Thank you so much for your help!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants