3

I'm debugging a C++ program, which contains quite some CPtrArray objects.
Using a customised heap_stat script, I know the pointer values of the CPtrArray objects, which contain a lot of entries.

Using native visualisers, I can indeed see the amount of entries in each CPtrArray object, hereby my corresponding natvis entry:

<Type Name="CArray&lt;*,*&gt;">
  <AlternativeType Name="CPtrArray"/> 
  <DisplayString>{{size = {m_nSize}}}</DisplayString> 

The problem is: this shows me the number of elements, but not the pointer value. I thought of solving this very easily, using the following natvis entry:

<Type Name="CArray&lt;*,*&gt;">
  <AlternativeType Name="CPtrArray"/> 
  <DisplayString>{{size = {m_nSize}, pointer = {this}}}</DisplayString> 

This, however, shows me the pointer value, but also lots more: :-)

{size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 {size = , pointer = }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}

Does anybody know how I can avoid this recursion?

Edit after first comment and answer

I've adapted my heap_stat script as follows:

if type_name.endswith("CPtrArray"):
  collection_Size = typedVar('CPtrArray', ptr).m_nSize
...
dprintln(("0x" + pointer_format + "\t%s\t Size:[%d]") % (ptr, type_name, collection_Size))

As a result of this, I get the sizes of the CPtrArray (and other) objects in my heap_stat report:

0x0732517c  mfc110u!CStringArray     Size:[0]
0x073256d4  mfc110u!CPtrArray    Size:[584]

I have COLUMN objects, who have a CPtrArray attribute, and I'd like to know which one corresponds with that particular CPtrArray object, therefore I've added all COLUMN objects in my watch window:

((COLUMN*)0x073256d0)->paData   {size = 584, pointer = 0x073256d4 {size = 584, pointer = 0x073256d4 ...
((COLUMN*)0x07325780)->paData   {size = 0, pointer = 0x01234567 {size = 0, pointer = 0x01234567 ...
((COLUMN*)0x07325830)->paData   {size = 0, pointer = 0x02345678 {size = 0, pointer = 0x02345678 ...

As you can see, the recursion is giving me enormous amounts of information (and heavily reducing the performance of my analysis), therefore I'd like to avoid it, without needing to expand every single COLUMN object for viewing the needed information.

Edit after some follow-up

As this issue looked like a bug in Natvis handling, I've decided to write a duplicate post on the MSDN website. That post has recently been tagged as "Triaged", which, I hope, means that it is taken into consideration by MSDN developers.

Thanks in advance

Dominique
  • 16,450
  • 15
  • 56
  • 112
  • The element's aren't at `this`, so why are you trying to display it? Surely they are at `m_pData` or somesuch? What's the layout of `CArray`? – Caleth Dec 10 '18 at 17:21
  • I'm not looking for the elements inside the `CPtrArray`, but the object itself: I'm working with heap_stat script, which gives object address, together with size (I've customised the heap_stat script for that), and when I find a `CPtrArray` object, I'd like to be able to confirm that is indeed the one I'm looking at in my Visual Studio watch-window. – Dominique Dec 11 '18 at 13:26
  • That still sounds like you have a `struct CPtrArray { size_t m_nSize; T * m_pData; };`, and want to look at the value of the data pointer. `this` is never going to be what you want the visualiser to show. – Caleth Dec 11 '18 at 13:31

2 Answers2

4

The recursive expansion is done because the debugger knows that this is of type CArray and how that type shall be displayed. If you just want the pointer without expansion you can drop the knowledge of the CArray type by casting the pointer to void* as in

<DisplayString>{{size = {m_nSize}, pointer = {(void*)this}}}</DisplayString>
Werner Henze
  • 16,404
  • 12
  • 44
  • 69
1

The issue is that you ask through natvis to display this recursively. this would display the DisplayString for this and now you have an infinite recursion. Actually very few natvis files have this in their DisplayString.

Add instead an <Expand> section with the content of the array and other contents, and this will not recurse.

You can display the pointer to the data instead, this is very easy to achieve, if you want to have some kind of check to recognize identical arrays, but with this, you won't be able to get the result you want because it triggers the display string with the pointer.

Matthieu Brucher
  • 21,634
  • 7
  • 38
  • 62