3

I have a stack-allocated std::vector that is being overwritten by some rogue code. It is not the data being overwritten, but the internal state. I know this because the size() member function returns a junk value some time into the program. It initialises correctly. I suspect a common pointer bug elsewhere in my code.

I am using Xcode 4.6.2. I want to set a hardware breakpoint (with lldb) upon memory access to the vector's first memory location (of the vector itself, not the data), so I can see what is overwriting it. According to this I need to first find the address of the vector. Normally one would use the & operator to get the address of a variable, but for some reason with lldb this doesn't return the address but instead prints some sort of summary string.

class myClass {
 public:
  myClass() : myVector(4) {}
 private:
  std::vector<double> myVector;
  double myDouble;
};

After breaking at an arbitrary breakpoint after everything is constructed:

(lldb) frame variable &myObject.myVector
(std::vector<double, std::allocator<double> > *) $7 = size=4

'expr' has the same result:

(lldb) expr &myObject.myVector;
(std::vector<double, std::allocator<double> > *) $8 = size=4

Normally I'd expect to see the address printed, such as with this plain data member:

(lldb) frame variable &myObject.myDouble
(double *) &myDouble = 0x0000000125589328

I tried assigning the address to a variable with 'expr' but that doesn't work either:

(lldb) expr std::vector<double, std::allocator<double> > * f = &myObject.myVector; f
(std::vector<double, std::allocator<double> > *) $12 = size=0

The zero size (instead of 4) returned there suggests it didn't actually pick up the right vector anyway.

So how do I get the address of this vector? If I right-click on it in Xcode's list of frame variables, and choose 'View Memory' of this vector, then it opens a view of 0x0 which of course is invalid. Note that the vector is allocated on the stack - it's actually inside a few other objects but all of these are stack constructed.

Please note that I am not wanting to obtain the address of the data within the vector - this isn't actually being overwritten. It is the internal storage of the stack-allocated vector object that is being damaged.

2
  • What you're seeing in the debugger is just lldb trying to be helpful and make it more human-readable. In code, though, you should be able to just use &myObject.myVector. You could always create variable to hold the address, like std::vector<whatever>* vecPtr = &myObject.myVector;. You could then see what lldb does with vecPtr, or use it in code. Commented Apr 23, 2013 at 11:59
  • I tried that variable idea, but when lldb prints that out it also formats it as a vector, since I suppose it knows it's a pointer to a vector. Perhaps I ought to have used a void *. Commented Apr 23, 2013 at 21:24

2 Answers 2

9

Your myObject object is likely a local variable and exists on the stack:

(lldb) p &myObject
(myClass *) $0 = 0x00007fff5fbffad8
(lldb) p $fp >= &myObject && &myObject >= $sp
(bool) $1 = true

If you want lldb to not pretty-print the vector, use the -R / --raw-output option to frame variable:

(lldb) fr va -R myObject
(myClass) myObject = {
  myVector = {
    std::_Vector_base<double, std::allocator<double> > = {
      _M_impl = {
        _M_start = 0x00000001001008d0
        _M_finish = 0x00000001001008f0
        _M_end_of_storage = 0x00000001001008f0
      }
    }
  }
  myDouble = 6.95322297580907e-310
}

You'll notice the addresses on the vector are heap addresses - that is, they were malloc'ed (new'ed, whatever) instead of being located inside your myObject directly. So now you have to decide what you want to monitor. If you want to monitor the vector to see a new element being added to the end of your vector, then you want to watch the end-of-vector pointer,

(lldb) p &myObject.myVector._M_impl._M_finish
(double **) $4 = 0x00007fff5fbffae0

If you want to monitor the contents of one of the vectors, say the first, then you want to monitor

(lldb) p myObject.myVector._M_impl._M_start
(double *) $6 = 0x00000001001008d0

of course when elements are added to the vector it may be moved to a new address range (if the memory region on the heap cannot be grown to hold the new element) so this is going to be a little fragile.

Normally lldb's type formatters (for std::vector in this case) are preferable to seeing the raw implementation -- but if you want to work with the raw implementation, it may be easier to disable the formatters in this case. e.g.

(lldb) type category disable  gnu-libstdc++
(lldb) p myObject
(myClass) $9 = {
  (std::vector<double, std::allocator<double> >) myVector = {
    (std::_Vector_base<double, std::allocator<double> >) std::_Vector_base<double, std::allocator<double> > = {
      (std::_Vector_base<double, std::allocator<double> >::_Vector_impl) _M_impl = {
        (double *) _M_start = 0x00000001001008d0
        (double *) _M_finish = 0x00000001001008f0
        (double *) _M_end_of_storage = 0x00000001001008f0
      }
    }
  }
  (double) myDouble = 6.95322297580907e-310
}

You can see all of the type formatters built-in to lldb with the type summary list command.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you, -R is the key here. This allows fr va -R &myObject.myVector and now displays the vector's address (of the object itself, not it's heap-based storage) instead of the size.
1

Just as an addendum, you should have been able to say: (lldb) watchpoint set expression &myVector even if you don’t really get to “see” the value

Also, what you were seeing was the summary for an std::vector - turns out that we were not instructing the summary to either not apply to pointers or to show the value as well.

I have made a fix to the open source LLDB that will allow you to see the numeric value of the pointer. Probably, the really correct solution, though, would have to be a special “for-pointers” summary format that shows value & summary. However, I am not overly enthusiastic with going down that route as it would duplicate the amount of regexp formatters we have in LLDB, which is potentially not the best thing to do for performance.

1 Comment

Thanks for the additional info.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.