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

NatVis Intrinsic substitution failure not supported #231

Open
k3DW opened this issue Oct 10, 2024 · 9 comments
Open

NatVis Intrinsic substitution failure not supported #231

k3DW opened this issue Oct 10, 2024 · 9 comments

Comments

@k3DW
Copy link

k3DW commented Oct 10, 2024

This may potentially be related to #217, since it's an inconsistency between Visual Studio and WinDbg.

I have a required use case in the Boost.Unordered library. In order to display the associative containers, I have a setup that boils down to this:

  • A class template
  • I need to detect properties about the type stored in the class from within the NatVis, so I can normalize it regardless of the type
  • I'm doing this with a <Intrinsic> elements that are "overloaded", using the attribute Optional="true"
  • This is effectively doing "substitution failure" with NatVis, to ensure only 1 overload is alive at any given time

Here is a very boiled-down example of the kind of thing I need. I need to normalize inner for various types it could possibly be, and extract its value, so that value can be used in other places in the visualization homogeneously.

#include <optional>
template <typename PointerLike>
struct MyStruct
{
    using InnerType = PointerLike;
    InnerType inner;
};
int main()
{
    int x = 5;
    MyStruct<int*> a{ &x };
    MyStruct<std::optional<int>> b{ x };
} // break here
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
    <Type Name="MyStruct&lt;*&gt;">
        <!--
            The expression `&**p` is used so the Intrinsic fails to parse for anything other than a raw pointer.
            For a raw pointer, this expression is exactly equivalent to `*p`.
            For an optional, this expression will try to call a user-defined `operator*()`, which is not allowed in Natvis, and it will fail.
        -->
        <Intrinsic Name="get_pointer" Optional="true" Expression="&amp;**p">
            <Parameter Name="p" Type="InnerType*" />
        </Intrinsic>
        <Intrinsic Name="get_pointer" Optional="true" Expression="&amp;(p->_Value)">
            <Parameter Name="p" Type="InnerType*" />
        </Intrinsic>
        <Expand>
            <Item Name="value">*get_pointer(&amp;inner)</Item>
        </Expand>
    </Type>
</AutoVisualizer>

This is fully supported in Visual Studio, however when I try to use cdb.exe, this does not work.

I would be happy to go into more detail to explain the use case further. Thank you!

@wmessmer-msft
Copy link

Thanks for the report. I'll note that there's a present known limitation in WinDbg's NatVis support that we do not handle overload resolution of NatVis methods in the traditional C/C++ sense (different parameter lists).

While this isn't quite the same, the WinDbg implementation appears to be conflating the two and failing here thinking that it needs to do unsupported overload resolution between the two get_pointer methods. In reality, only one applies because of the parse error / optional. We'll take a look at fixing for that kind of usage.

@k3DW
Copy link
Author

k3DW commented Oct 10, 2024

Ah I see. I also have regular overloads, in the sense of different parameter lists, but I can change those in my case. However don't think I can make my visualizers work without overloading with substitution failure.

I have another related question. Is there a way to output NatVis errors with WinDbg, similarly to what can be done in Visual Studio? It's difficult to tell what the errors are without a verbose error output, and I haven't been able to figure out how to do that.

Thank you for the help!

@wmessmer-msft
Copy link

Unfortunately, there isn't currently a "verbose" error output from WinDbg's NatVis parser.

@k3DW
Copy link
Author

k3DW commented Oct 10, 2024

Got it. Thanks for the help and the quick replies! I'll check back for any updates.

@ge0rdi
Copy link

ge0rdi commented Oct 11, 2024

@wmessmer-msft
I'm wondering why does WinDbg use different NatVis implementation than Visual Studio.
It is rather annoying to create visualizer in VS just to discover that it doesn't work properly in WinDbg.

@wmessmer-msft
Copy link

@wmessmer-msft I'm wondering why does WinDbg use different NatVis implementation than Visual Studio. It is rather annoying to create visualizer in VS just to discover that it doesn't work properly in WinDbg.

WinDbg and Visual Studio are very different debuggers with very different debug engines. The NatVis implementations are, unfortunately, somewhat tied to that underlying debug engine.

The aim is to (largely) share the specification and make them as compatible with each other as possible. There are a few "documented" differences between the two. The most significant of these:

  • NatVis "views" have slightly different meaning. Right now, WinDbg "gloms" all the views together.
  • VS has a few NatVis elements that allow callback into VS specific plug-ins (that obviously we do not support and just ignore if we see)

Most other "incompatibilities" end up being bugs that we try to fix when they are reported.

Some of those differences (e.g.: views) stem from the fact that WinDbg uses NatVis very differently than Visual Studio. WinDbg integrated NatVis as part of its data model and not just for visualization. That means that anything you add via NatVis is accessible everywhere (locals/watch/scripts). It's why, for instance, you can write a WinDbg JavaScript script that gets passed a std::vector<> and just does:

for (var item of myVector) { ... }

That "for...of" goes to our concept of an iterated (COM level = IIterableConcept) object (COM level == IModelObject) which goes to the NatVis provided data model which is attached to it.... and runs what's in the provided stl.natvis to actually iterate the object.

Likewise, you can do similar from a C COM API, from a C++17 API, etc... or you can extend a NatVis from JavaScript.... or C++17, etc...

@KindDragon
Copy link

Hi. Does VS Code use the same Natvis engine as WinDbg or a different implementation?

@wmessmer-msft
Copy link

@KindDragon : WinDbg's implementation is separate from anything VS / VSCode does.

This has been fixed internally and should be available in a subsequent public debugger release. Note that, at the moment, this fixes the issues around using "Optional" and having parse errors in Intrinsic methods (and a number of related issues). It does not yet introduce full C/C++ overload resolution if there are multiple Intrinsic overloads of the same name (but different parameter) lists which potentially apply.

@k3DW
Copy link
Author

k3DW commented Nov 4, 2024

That's amazing, thank you!

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

No branches or pull requests

4 participants