Skip to content

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

@dmachaj

Description

@dmachaj

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions