7

In Visual Studio 2017, I have create a .natvis debugger visualization rule which calls a C++ function.

In the debugger it shows:

This expression has side effects and will not be evaluated.

Beside this, it shows a little blue arrow that can be clicked on to force it to evaluate, and then it actually does call the function. (I think this might be a recent feature, because I seem to remember trying this in VS2013 and don't remember it having a bypass)

My question is: Is there some way I can permanently bypass this safety check, so that it always evaluates my function immediately and doesn't require me to click on the arrow?

I have looked at a very similar question: "This expression causes side effects and will not be evaluated". How to suppress? where the accepted answer is only valid for C# (adding ,ac on the end of a C# expression forces the debugger to automatically re-evaluate it)

I imagine if such a thing existed it would be one of the following mechanisms:

  1. A registry setting or other global setting that disables the safety check all the time.
  2. A way of annotating the code or the .natvis rule so that the compiler knows somehow that it's a safe and pure side-effect-free function

To give a bit more detail about the application: We use uint32's all over the place in our code which are hashed from strings, and we have a database of the strings loaded only in development builds. The decoding function looks up the u32 ID in a binary search tree, returning the string found in the stored node. So I know that it's entirely side-effect-free and sufficiently fast that it not impair the debugging experience to just call the function each time the .natvis rule says so.

uglycoyote
  • 1,555
  • 1
  • 19
  • 25
  • Does the search return a copy of the string in a freshly allocated buffer? If so, that is a side effect. Perhaps you can pre-allocate some debug buffer and use a string-search API that just populates it? – Ofek Shilon Nov 02 '17 at 10:45
  • Also, it seems that if your functions internally construct any objects, it is enough to have them declared as having side effects: https://msdn.microsoft.com/en-us/library/za56x861.aspx – Ofek Shilon Nov 02 '17 at 10:48
  • @OfekShilon no, there are no side effects, no freshly allocated buffers, the strings are all stored in a big table and it returns a const char* to the correct string that it finds. Also, I don't think that the debugger/compiler is actually inspecting the function for side-effects, my impression is that it's just taking a cautious approach of assuming guilt because it is hard to prove innocence. I mean even if the code is theoretically side-effect free, it is still changing the value of registers, time is still passing, therefore things are not in the same state after it runs, right? – uglycoyote Nov 03 '17 at 00:10
  • Afaik the expression evaluator hijacks the stack of the current debugee thread, performs the evaluation and then cleans the stack and restores the original thread context (=registers). Perhaps you can post runnable code for the function the EE refuses to run? – Ofek Shilon Nov 03 '17 at 08:50
  • how about `int MyTestFunction() { return 56;}`. Debugger says "This expression has side effects and will not be evaluated." have I convinced you yet that it does not care what your code actually does and always considers it to have side-effects? – uglycoyote Nov 06 '17 at 20:54
  • What happens when you type 'MyTestFunction()' at the debugger watch window? When I do, it shows 56. – Ofek Shilon Nov 12 '17 at 19:41
  • It will evaluate it when you type it in to the watch window and hit enter, I guess the rationale is that you are being explicit about wanting to evaluate it at that moment. But if you continue and break again you will see it greyed out, and if you hover it, it will have a similar message to the one that I mentioned above, saying that it's avoiding re-evaluating it because it may have side effects. You can manually re-evaluate it by clicking the round arrow (as you can with .natvis rules that call functions) but I was hoping to avoid that manual step on each time hitting a breakpoint. – uglycoyote Nov 14 '17 at 15:44

2 Answers2

6

Upon further research, I suspect there's no way to tell Visual Studio that your function has no side-effects, and even for a trivially side-effect-free function such as int MyTestFunction() { return 56; } it will still give the "expression has side effects and will not be evaluated" message in the watch window.

Although it's not a very satisfactory answer, I did find a way around this problem, which was to re-implement the function I was trying to call (a binary search through a table, in my case) using the awkward, ugly XML syntax of .natvis's CustomListItems tag.

Despite the name of this tag implying that it has something to do with lists, it appears that this tag is a kind of a catch-all for any visualizer which requires some kind of algorithm to implement. Underneath <CustomListItems> you are allowed to use a bunch of different tags which are probably sufficient to implement just about any algorithm:

  • <Variable> tags to declare variables,
  • <Loop> tag for iterating,
  • <Break Condition="myCondition"> for checking whether to terminate the loop,
  • <Exec> tags for executing expressions, mutating the values of the variables declared in <Variable> tags,
  • <If Condition="myCondition"> for branching
  • You can include any number of <Item Name="name">value</Item> tags, each of these will appear as a row in the watch window underneath the variable that's being expanded.

As far as I can tell most of these algorithmic tags can only be used under CustomListItems (I tried just a regular <Expand> rule using some <Variable> tags and got errors indicating that it was not supported)

It's not very pleasant to have to re-implement a C++ function that already works in this terrible syntax (keep in mind gotchas like having to use &gt; and &lt; in place of > and < because it's XML).

However, with the following couple of tips, it's not as terrible as it could be

  • If you edit the .natvis file from within visual studio, saving the file triggers the debugger to re-evaluate the display without needing to restart your program, so iterating on your .natvis rule is pretty fast. (note: this does not seem to work for me in VS2017 when editing the .natvis file from an external editor)
  • Using lots of <Item> tags within your rule, you can basically do the equivalent of "print debugging". While trying to get your .natvis rule to work, use <Item> to print out intermediate values. This will make it much easier to track down where the algorithm is failing if it's not working properly. Delete these extra tags when it's working.

You can find documentation and an example of CustomListItems here.

https://msdn.microsoft.com/en-us/library/jj620914.aspx

uglycoyote
  • 1,555
  • 1
  • 19
  • 25
  • Basically the excuse is safe native function execution is hard: https://developercommunity.visualstudio.com/content/problem/203173/natvis-function-call-not-allowed.html – Trass3r Nov 12 '18 at 06:59
  • Very useful, thanks a lot!. Too bad Microsoft doesn't document it properly. Now I need a way to affect the node to show that calculated value. – egur Jan 22 '23 at 18:06
1

I had the same problem and while searching I've come to this topic.

I've just found a solution and wanted to post here: If you define a function as Intrinsic in the XML then the compiler does not show anything like This expression has side effects... when you call that intrinsic function.

Here's an example:

I wrote a custom string class and it is something like this:

namespace rkstl
{
    namespace strings
    {
        //null-terminated string object consisting of 'char' elements
        class string 
        {
         public:    
             //... c'tors, copy c'tor and d'tor come here

             length(); //returns the length of null-terminated string: _mSize
             capacity(); //returns the length of the actual buffer: _mCap
             clear();

             //... other member functions

         private:
             char* _pStr; //the actual buffer
             size_t _mSize; //length of the string
             size_t _mCap; //length of the actual buffer
        };

        //null-terminated wide string object consisting of 'wchar_t' elements
        class wstring
        {
         //...
        };

    }
}

You can see from my implementation that length() and capacity() are intrinsic functions. So, if I call them in directly the .XML then the compiler will show This expression has side effects... so I will have to click the re-evaluate button (blue circled-arrow) to see what the data is:

<Type Name="rkstl::strings::string">
<DisplayString>{_pStr,na}</DisplayString>
<StringView>_pStr,na</StringView>
<Expand>
  <Item Name="[string length]" ExcludeView="simple">length()</Item>
  <Item Name="[buffer capacity]" ExcludeView="simple">capacity()</Item>
  <ArrayItems>
    <Size>_pEnd - _pBegin</Size>
    <ValuePointer>_pStr</ValuePointer>
  </ArrayItems>
</Expand>

Instead, I define intrinsic functions evaluating the same things as in the class. And I can call them directly in the .natvis XML. Here's my .natvis implementation for rkstl::strings::string:

<Type Name="rkstl::strings::string">
<Intrinsic Name="length_dbg" Expression="(_mSize)"/>
<Intrinsic Name="capacity_dbg" Expression="(_mCap)"/>
<DisplayString>{_pStr,na}</DisplayString>
<StringView>_pStr,na</StringView>
<Expand>
  <Item Name="[length of the string]" ExcludeView="simple">length_dbg()</Item>
  <Item Name="[capacity of the buffer]" ExcludeView="simple">capacity_dbg()</Item>
  <ArrayItems>
    <Size>_pEnd - _pBegin</Size>
    <ValuePointer>_pStr</ValuePointer>
  </ArrayItems>
</Expand>

You can see that I've defined length_dbg() and capacity_dbg() as Intrinsic. So, the debugger can safely call them and evaluate the data that I want to show. Here's the result:

enter image description here