3

I have a class Foo, which has a (simple) destructor.

Some other class contains an array of Foo objects (called foolist), in the destructor of that class, I do:

delete[] foolist;

This crashes (gdb shows that it crashes in this exact line). However, by using printouts I see that all the elements in foolist are finishing their destructor without problems (the number of destructors that runned is also equal to the number of objects allocated in this array, so they all get destructed). There is also no other delete for foolist in the code.

I also made sure that foolist is indeed initialized as an array, in this way:

foolist = new Foo[number];

The error is:

*** glibc detected *** /home/bas/projects/trunk/main:
free(): invalid next size (fast): 0x080a0e80 ***

What could cause delete[] to crash in this case?

Thanks in advance!

As asked also the output of valgind here (statementNode is Foo, and programNode the class containing list of Foo's)

==4111== 1 errors in context 1 of 2:
==4111== Invalid write of size 4
==4111==    at 0x804B6FA: Parser::parseProgram(std::string) (statementnode.h:35)
==4111==    by 0x80764D4: main (parser.h:35)
==4111==  Address 0x42d9bdc is 4 bytes after a block of size 32 alloc'd
==4111==    at 0x4025F53: operator new[](unsigned int) (vg_replace_malloc.c:299)
==4111==    by 0x804A81E: Parser::parseProgram(std::string) (programnode.h:21)
==4111==    by 0x80764D4: main (parser.h:35)

StatementNode:35 is the creation of a completly different object. ProgramNode:21 is the creation of foolist / list of StatementNodes.. Hope this helps.

openbas2
  • 263
  • 1
  • 7
  • 16
  • We could use a bit more context: - Is your class Foo a simple class, or is it in a type hierarchy, perhaps involving multiple inheritance? - Have you overridden the memory allocator, the new operator? - Does your Foo type have members that are themselves full-blown objects (i.e. not base types or pointers)? - What's the type of foolist pointer (just in case)? – Xavier Decoret Aug 30 '11 at 15:58
  • 3
    You've probably corrupted your heap by deleting something twice, mismatching some pair of `new`, `new[]`, `malloc`, `delete`, `delete[]`, and `free`, or by freeing/deleting a pointer that doesn't point to a dynamically allocated object. – James McNellis Aug 30 '11 at 15:59
  • Imposable to say without more information. What does the class Foo look like. – Martin York Aug 30 '11 at 16:02
  • Foo is not really a simple class (holds datamembers that hold other datamembers and so on.....), but multiple inheritance is not used. – openbas2 Aug 30 '11 at 16:03
  • @openbas2: It can also error if single inheritance is used. – Puppy Aug 30 '11 at 16:15
  • Can you post the source code in `Parser::parseProgram(std::string)`? The Heap corruption is happening there, You are writing 4 bytes beyond the allocated memory in that function. – Alok Save Aug 30 '11 at 16:18
  • @DeadMG: what kind of error would I look for in that case? – openbas2 Aug 30 '11 at 16:24
  • @Als: I cannot post the code here (its huge, bad coding style I know :( ), but that gives me a place to start. I also found that the valgrind log is pointing to an other class in the parseProgram function, so maybe the problem is with an allocation there. I have to leave now, will report back tomorrow with the results. Thanks so far! – openbas2 Aug 30 '11 at 16:27

3 Answers3

7

The delete operator performs 2 functions under the hood

  1. Run Destructors
  2. Free Memory

Given the printout confirms #1 is happening the most likely cause is a crash during the actual freeing of memory (the message indicates this as well). This typically indicates that the memory is being corrupted by another part of your program.

Have you tried running your program under valgrind?

JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • Didn't think of valgrind, and it indeed shows a problem (Foo from the original quesion is statmentNode here, and the containing class is programNode, wanted to keep the original question simple...) See next comment for the output – openbas2 Aug 30 '11 at 16:08
  • ==4111== 1 errors in context 1 of 2: ==4111== Invalid write of size 4 ==4111== at 0x804B6FA: Parser::parseProgram(std::string) (statementnode.h:35) don't yet know what to make of this, maybe I need to look at valgrind docs more.... ==4111== by 0x80764D4: main (parser.h:35) ==4111== Address 0x42d9bdc is 4 bytes after a block of size 32 alloc'd ==4111== at 0x4025F53: operator new[](unsigned int) (vg_replace_malloc.c:299) ==4111== by 0x804A81E: Parser::parseProgram(std::string) (programnode.h:21) ==4111== by 0x80764D4: main (parser.h:35) – openbas2 Aug 30 '11 at 16:09
  • sorry for the (lack of) markup, apparently doesn't work in comments... :( – openbas2 Aug 30 '11 at 16:10
  • @openbase2 can you add the output to the question? I'm not extremely familiar with valgrind and it will get more visibility if it's in your question. – JaredPar Aug 30 '11 at 16:10
  • Added it to the question. Given that valgrind shows a problem with a completely unrelated class, corruption seems likely indeed... – openbas2 Aug 30 '11 at 16:17
6

Looks like our good old pal "undefined behaviour".

Maybe foolist is deleted twice. Have you overloaded the class' copy constructor and assignment operator? If not, you should read this: What is The Rule of Three?

Community
  • 1
  • 1
Etienne de Martel
  • 34,692
  • 8
  • 91
  • 111
  • 2
    +1, **Rule of Three**, The usually missed out fundamental.You might as well link to the FAQ. – Alok Save Aug 30 '11 at 16:02
  • Thanks for your answer, I checked them, and I have overloaded both. I also checked using printouts, and it seems they are not even used before the crash... – openbas2 Aug 30 '11 at 16:22
2

You could have double deleted it- even unintentionally by violating the Rule of Three. You could have changed the value of the pointer- e.g. incrementing it. You could have polymorphically converted it, e.g. Base* ptr = new Derived[size]; delete[] ptr; which is also undefined behaviour.

Lesson: Always, always, always use a smart pointer.

Puppy
  • 144,682
  • 38
  • 256
  • 465