开发者

Instruction pointer strange behavior

I'm experiencing a very weird problem.

Let's say I have a class, a public member of which is a vector of pointers to some type:

class SystemState
{
  // ...
public:
  SystemState (const SystemState& s); // copy constructor
  std::vector <Concept *> m_L;
  // ...
};

I fear it is important to know that the Concept class has some virtual methods, among which:

virtual enum ConceptType GetType (void) const;

The vector usually stores pointers to classes that inherit from the base Concept class.

At some point, when calling SystemState copy constructor, the program crashes due to segmentation fault. I must say that such copy constructor was already been called many times before, and it didn't cause any problem.

Valgrind does not report any problem: - no definitely lost bytes, no indirectly lost bytes (only possibly lost+still reachable bytes, due to std::string) - no invalid reads, no invalid writes - when attaching GDB to Valgrind, nothing happens, as Valgrind does not spot any error.

Intrestingl, inspecting the code by means of GDB alone reveals the the extended instruction pointer, goes haywire without a reasonable explanation. Here's a debugging session:

SystemState (this=0xbfffecf4, s=...) at system-state.cc:14
14  SystemState::SystemState (const SystemState& s) // copy constructor
(gdb) n
16    for (uint32_t i = 0; i < s.GetSize (); i++)
(gdb) n
18      if (s.m_L[i]->GetType() == Concept::GENERIC)
(gdb) s
std::vector<sim::Concept*, std::allocator<sim::Concept*> >::operator[] (this=0x80a5d88, __n=0) at /usr/include/c++/4.3/bits/stl_vector.h:578
578       { return *(this->_M_impl._M_start + __n); }
(gdb) fin
Run till exit from #0  std::vector<sim::Concept*, std::allocator<sim::Concept*> >::operator[] (this=0x80a5d88, __n=0)
    at /usr/include/c++/4.3/bits/stl_vector.h:578
0x080782ab in SystemState (this=0xbfffecf4, s=...) at system-state.cc:18
18      if (s.m_L[i]->GetType() == Concept::GENERIC)
Value returned is $30 = (class sim::Concept * const&) @0x80a6400: 0x80a6698
(gdb) si
0x080782ad  18      if (s.m_L[i]->GetType() == Concept::GENERIC)
(gdb)
0x080782af  18      if (s.m_L[i]->GetType() == Concept::GENERIC)
(gdb)
0x080782b4  18      if (s.m_L[i]->GetType() == Concept::GENERIC)
(gdb)
0x080782b7  18      if (s.m_L[i]->GetType() == Concept::GENERIC)
(gdb)
0x080a5b10 in ?? ()
(gdb) info fr
Stack level 0, frame at 0xbfffeca0:
 eip = 0x80a5b10; saved eip 0x807bc84
 called by frame at 0xbfffed50
 Arglist at 0xbfffec98, args:
 Locals at 0xbfffec98, Previous frame's sp is 0xbfffeca0
 Saved registers:
  ebp at 0xbfffec98, eip at 0xbfffec9c
0x080a5b12 in ?? ()
(gdb)
0x080a5b14 in ?? ()
(gdb)
0x080a5b15 in ?? ()
(gdb)
0x080a5b17 in ?? ()
(gdb)

Program received signal SIGSEGV, Segmentation fault.
0x080a5b17 in ?? ()
(gdb)

As a side information, Concept::GENERIC is an entry of enum Concept::ConceptType. As can be seen, the vector is accessed without problems (). Then, something strange happens.

What puzzles me most is that, that part of code has already been called several times before.

I have absolutely no idea what else to look for, nor I have ideas how to debug the code. So, either you have the solution to this mystery or debugging tips, you're most welcome!

PS: complete files can be found here: http://mercurial.intuxication.org/hg/lte_sim/file/544cef78b03d/src

Update 1

Following Rob's suggestion, I defined operator= as follows:

SystemState&
SystemState::operator= (const SystemState& s)
{
  for (uint32_t i = 0; i < GetSize (); i++)
  {
    m_L[i] = s[i]->Clone ();
  }

  return *this;
}

The program does not crash anymore, but is leaking memory: as you can see we store another object without releasing the memory of the old one. Now, if I issue a delete (m_L[i]); right before the assignment, the program crashes again, even if the pointer is pointing to a valid object (checked with GDB, but I need to check it more accurately).

开发者_运维百科Update 2 I decided to move to boost::shared_ptr, so that explicit delete is not needed anymore.


Rule of Three:

If a class defines one of the following it should probably explicitly define all three[1]:

  • destructor
  • copy constructor
  • copy assignment operator

Your class SystemState defines a destructor and a copy constructor, but not a copy assignment operator. Consider:

SystemState t;
{
    SystemState s;
    s.AddConcept(new ...);
    t = s;
}

After the assignment operation, t and s have identical m_L vectors. That is, they both contain pointers to a Concept that was added to s. At the end of the block in which s is declared, s goes out of scope and is destroyed. ~SystemState deletes the pointer, but t still holds it. Now t has a pointer in its m_L that points to a destroyed object. As soon as t does anything interesting (including going out of scope and being destroyed itself), it invokes undefined behavior.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜