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

Bug: Projected winrt::consume_ methods will nullptr crash if the underlying QueryInterface call fails #1441

Closed
dmachaj opened this issue Oct 28, 2024 · 0 comments · Fixed by #1442

Comments

@dmachaj
Copy link
Contributor

dmachaj commented Oct 28, 2024

Version

2.0.24040

Summary

The generated projection code for interfaces that the metadata declares as required for a runtimeclass assume that QueryInterface never fails. Assuming the metadata is correct in the first place, this is a valid assumption for inproc calls.

However, for cross-process calls the QI can fail even if the metadata is correct and the class really does implement all of the required interfaces. It can fail with E_ACCESSDENIED and a variety of other RPC error codes.

When this happens there is a nullptr crash in the generated consume method. This can be very painful to debug because the HRESULT is lost by the time it crashes.

Reproducible example

IDL file:

namespace CrashRepro
{
    // This class declares that it implements another interface but under the covers it actually does
    // not.  This allows us to test the behavior when QI's that should not fail, do fail.
    runtimeclass LiesAboutInheritance : Windows.Foundation.IStringable
    {
        void StubMethod();
    }
}

main.cpp:

#include <winrt/CrashRepro.h>

namespace
{
    struct LiesAboutInheritance : public winrt::implements<LiesAboutInheritance, winrt::CrashRepro::ILiesAboutInheritance>
    {
        LiesAboutInheritance() = default;
        void StubMethod() {}
    };
}

int main()
{
    init_apartment();

    auto lies = winrt::make_self<LiesAboutInheritance>().as<winrt::CrashRepro::LiesAboutInheritance>();
    FAIL_FAST_IF_NULL(lies);
    lies.ToString();     // this line will nullptr crash
}

Expected behavior

Ideally it would throw an invalid cast exception that can be caught/handled. Less ideally it should fail with a clear signature.

Actual behavior

There is a nullptr dereference crash. It has unwound enough before crashing that the HRESULT is permanently lost so it is very difficult to debug.

Additional comments

No response

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