Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constructor called with wrong "this" pointer. Is this stack corruption?

edit: I've figured it out with the help of commenters. To answer the question posed in my title: No, it is not stack corruption, its gdb reporting the wrong values. The program actually behaves as expected and has the right this pointer. The actual buggy behaviour which prompted me to post this question is probably completely unrelated to the issue I describe here.

First a warning. I believe this is a memory corruption issue, and I would normally not expect an answer except for "check your code thoroughly", but I've seen this behaviour pop up repeatedly and was hoping some of you had insight on the problem and how I can find its source.

I'm currently implementing an interval static analysis which tracks the possible range of variables in a C program. The copy constructor for my base interval class looks like this:

itvt::itvt(const itvt& i)
  : _i(i.type == INTBV ? new intbv_intervalt(i.i()) : NULL),
    _f(i.type == FLOAT ? new float_intervalt(i.f()) : NULL),
    type(i.type), other_bottom(i.other_bottom) 
{ }

Now, I found a memory corruption bug and managed to trace it to the following snippet of code:

itvt itvt::get_split(bool le) const
{
   itvt result(*this);
   [...]
}

Using gdb, I find that the call to the constructor does not seem to construct the "result" object:

Breakpoint 1, itvt::get_split (this=0x1016af560, le=false) at itv.cpp:517
517   itvt result(*this);
(gdb) n
519   if(is_singleton() || is_bot())
(gdb) print result
$3 = {
  _i = {
    _M_ptr = 0x7fff5fbfe100
  }, 
  _f = {
    _M_ptr = 0x7fff5fbfed60
  }, 
  type = 1606410016, 
  other_bottom = 255
}
(gdb) print *this
$4 = {
  _i = {
    _M_ptr = 0x1020833a0
  }, 
  _f = {
    _M_ptr = 0x0
  }, 
  type = itvt::INTBV, 
  other_bottom = false
}

Looking deeper, I find that inside the copy constructor, the "this" pointer points to the wrong object:

Breakpoint 1, itvt::get_split (this=0x1016af560, le=false) at itv.cpp:517
517   itvt result(*this);
(gdb) print &result
$5 = (itvt *) 0x7fff5fbfdee0
(gdb) s     
itvt::itvt (this=0x7fff5fbfdf80, i=@0x1016af560) at itv.cpp:500
500     type(i.type), other_bottom(i.other_bottom)
(gdb) print this
$6 = (itvt * const) 0x7fff5fbfdf80

Since "result" is allocated on the stack at address 0x7fff5fbfdee0, I would expect the "this" pointer inside the copy constructor to point to the same address. Instead it points to 0x7fff5fbfdf80.

It looks like the copy constructor is initialising something, but not the "result" object on the stack on which it is called. In fact, I can access the memory location that the constructor initialised perfectly well:

Breakpoint 1, itvt::get_split (this=0x1016af560, le=false) at itv.cpp:517
517   itvt result(*this);
(gdb) s    
itvt::itvt (this=0x7fff5fbfdf80, i=@0x1016af560) at itv.cpp:500
500     type(i.type), other_bottom(i.other_bottom)
(gdb) finish
Run till exit from #0  itvt::itvt (this=0x7fff5fbfdf80, i=@0x1016af560) at itv.cpp:500
itvt::get_split (this=0x1016af560, le=false) at itv.cpp:519
519   if(is_singleton() || is_bot())
(gdb) print *((const itvt*) (0x7fff5fbfdf80))
$7 = {
  _i = {
    _M_ptr = 0x1016b6d10
  }, 
  _f = {
    _M_ptr = 0x0
  }, 
  type = itvt::INTBV, 
  other_bottom = false
}

My first question: Can the fact that the "this" pointer points to the wrong object be explained as normal behaviour? It seems like some weird memory corruption issue, but maybe I'm missing something.

I'm compiling with g++ and "-O0 -ggdb" flags and did a fresh recompile of everything btw. Here's my g++ version:

leo@scythe ai$ g++ --version
i686-apple-darwin11-llvm-g++-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)
Copyright (C) 2007 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

My second question: If it is memory corruption, do you have any advice on how I can track down the source. I usually follow such issues to their root cause using gdb, but I don't know where to look now.

This is not the first time I encounter this specific behaviour. I've seen it happen when looking into other people's bugs. I've never actually directly managed to address it directly, it just stopped happening or at least being a visible issue after some other code change. This leads me to believe that maybe its just an odd artefact of looking at the stack using gdb.

I thankful for any advice or insight you can offer.

edit: Here are is the relevant snippet of the itvt class:

class itvt
{
protected:
  typedef std::auto_ptr<intbv_intervalt> iptrt;
  typedef std::auto_ptr<float_intervalt> fptrt;
  iptrt _i;
  fptrt _f;
public:
  typedef enum {INTBV, FLOAT, OTHER} itv_typet;
  itv_typet type;

  bool other_bottom;

  //copy constr
  itvt(const itvt& i);

  inline intbv_intervalt& i() { return *_i; }
  inline float_intervalt& f() { return *_f; }
  inline const intbv_intervalt& i() const { return *_i; }
  inline const float_intervalt& f() const { return *_f; }

  itvt get_split(bool le) const;

  [...]
};
like image 497
leo Avatar asked Mar 01 '12 13:03

leo


2 Answers

Second question : use valgrind, it’s really what you need here. It tracks down every allocation / free, and tells you if you try and use freed memory, as well as lots of other stuff. It’ll show you a memory corruption.

like image 187
qdii Avatar answered Nov 05 '22 08:11

qdii


I've figured it out with the help of commenters: It looks like gdb is not telling the truth, (possibly due to an old gdb version). The program actually behaves as expected.

The actual buggy behaviour which prompted me to look into the issue was completely unrelated to the object initialisation.

like image 2
leo Avatar answered Nov 05 '22 08:11

leo