views:

176

answers:

2
+1  Q: 

STL list exception

Hello, I was trying to use an STL list in C++ and I arrived into a strange exception that I'm not able to understand.

The list is defined as list<ASTNode*> m_stats; and ASTNode* is a class. When I try to add elements by calling

ASTNode *node = new ASTNode();
m_stats.push_back(node);

it throws the following exception:

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00000004
0x91c20fe7 in std::_List_node_base::hook()

I tried to debug with gdb and inspected value inserted, is it not null and it is exactly what it should be..

the backtrace is:

#0  0x91c20fe7 in std::_List_node_base::hook ()
#1  0x0000a9fb in std::list<ASTNode*, std::allocator<ASTNode*> >::_M_insert (this=0x180344, __position={_M_node = 0x0}, __x=@0xbffff094) at stl_list.h:1152
#2  0x0000aa27 in std::list<ASTNode*, std::allocator<ASTNode*> >::push_front (this=0x180344, __x=@0xbffff094) at stl_list.h:743
#3  0x0000aa45 in ASTStatements::addStatement (this=0x180340, stat=0x180410) at ast.h:277

Am I missing something?

EDIT: added class source

class ASTStatements : public ASTNode
{
list<ASTNode*> m_stats;

public:
 ASTStatements() {}

 ASTStatements(list<ASTNode*> stats)
 {
  std::copy(stats.begin(), stats.end(), m_stats.begin());
 }

 ASTStatements(const ASTStatements &other)
 {
  std::copy(other.m_stats.begin(), other.m_stats.end(), m_stats.begin());
 }

 ASTStatements &operator= (const ASTStatements &other)
 {
  if (&other != this)
  {
   std::copy(other.m_stats.begin(), other.m_stats.end(), m_stats.begin());
  }
 }

 ASTStatements *clone()
 {
      return new ASTStatements(*this);
     }

     u8 type()
     {
      return 0;
     }

     const char *generateASM()
     {
      list<ASTNode*>::iterator it = m_stats.begin();

      while (it != m_stats.end())
      {
       ((ASTNode*)*it)->generateASM();
       ++it;
      }
     }

     void addStatement(ASTNode *stat)
     {
      m_stats.push_front(stat);
     }

     u8 typeCheck()
     {
      return 0;
     }
};

I used it in a bison grammar file to handle multiple statements (didn't find a better way to handle a generic list of items in a non terminal) in this way:

statements:
    statement { if ($$ == null) $$ = new ASTStatements(); ((ASTStatements*)$$)->addStatement($1); } statements { $$->generateASM(); }

;

Thanks in advance

A: 

There was most likely something you did to your list that occurred before the lines of code you posted. I'd suggest looking at all places m_stats is used and double check your use of it. You could post your uses of m_stats here and we could try helping you some more.

Polaris878
+3  A: 

Your constructors and assignment statements are wrong. When you call std::copy, there must already be enough space at the destination iterator to accommodate everything you're copying into it. The list won't grow by itself. The error message you're getting suggests you're overwriting some memory, and that's likely exactly what happens when you try to copy into a list that isn't big enough. (Formally, the behavior is undefined.)

You could use a std::back_insert_iterator, which is an iterator adapter that appends items to the underlying container instead of overwriting the current location. Create one using the std::back_inserter helper function from the <algorithm> header:

std::copy(stats.begin(), stats.end(), std::back_inserter(m_stats));

Better yet, though, is to skip all the copying and let the list's own constructors and assignment operators take care of it for you, as they're designed to:

ASTStatements(list<ASTNode*> stats)
  : m_stats(stats)
{ }

ASTStatements& operator=(const ASTStatements& other)
{
  m_stats = other.m_stats;
}
Rob Kennedy
sbi