?
Solved

C++ vector deallocation problem

Posted on 2011-05-02
28
Medium Priority
?
1,140 Views
Last Modified: 2012-05-11
Dear experts,

In my MFC application, I have a CParagraph class which has the following member:
std::vector<CTake> m_vectorWaveTakes;

CTake is a structure that has no pointers, just integers and booleans.
When CParagraph is destroyed, I am getting an error:

Book.exe has triggered a breakpoint
The thread 'Win32 Thread' (0x12e8) has exited with code 0 (0x0).
HEAP[Book.exe]: Invalid Address specified to RtlValidateHeap( 01170000, 016428F8 )
Windows has triggered a breakpoint in Book.exe.
This may be due to a corruption of the heap, which indicates a bug in Book.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while Book.exe has focus.
The output window may have more diagnostic information.

The call stack shows that the problem happened in the vector destructor, but I don't know what could cause it.
Thanks.
0
Comment
Question by:tantormedia
  • 15
  • 10
  • 3
28 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 35507904
Could you post the code for 'CTake'?
0
 

Author Comment

by:tantormedia
ID: 35507925
Here it is:
struct CTake
{
	CTime recordTime;
	DWORD waveLoc;
	int waveSize;
	int totalRaw;
	DWORD thisWaveTakeLoc;
	DWORD nextWaveTakeLoc;
	short waveCenter;
	short waveAveLevel;
	short waveMinNoise;
	BOOL  waveClipped;

	CTake() : recordTime(CTime::GetCurrentTime()), waveLoc(0), waveSize(0), totalRaw(0), thisWaveTakeLoc(0), nextWaveTakeLoc(0), waveCenter(0), waveAveLevel(0), waveMinNoise(0), waveClipped(FALSE){}
	CTake(CTime& time, DWORD loc, int size, int totRaw, short center, short level, short noise, BOOL clipped) : recordTime(time), waveLoc(loc), waveSize(size), totalRaw(totRaw), thisWaveTakeLoc(0), nextWaveTakeLoc(0), waveCenter(center), waveAveLevel(level), waveMinNoise(noise), waveClipped(clipped){}
};

Open in new window

0
 
LVL 86

Expert Comment

by:jkr
ID: 35507974
Are you performing any 'erase()' operations on the vector? Also, does this also occur if you provide a copy constructor plus an assignment operator for 'CTake'?
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:tantormedia
ID: 35508096
No, I am not using erase().
I added the copy constructor and an assignment operator, and still got an error

Error      7      error C2558: struct 'CTake' : no copy constructor available or copy constructor is declared 'explicit'      c:\Program Files\Microsoft Visual Studio 9.0\VC\include\vector      1211

struct CTake
{
	CTime recordTime;
	DWORD waveLoc;
	int waveSize;
	int totalRaw;
	DWORD thisWaveTakeLoc;
	DWORD nextWaveTakeLoc;
	short waveCenter;
	short waveAveLevel;
	short waveMinNoise;
	BOOL  waveClipped;

	CTake() : recordTime(CTime::GetCurrentTime()), waveLoc(0), waveSize(0), totalRaw(0), thisWaveTakeLoc(0), nextWaveTakeLoc(0), waveCenter(0), waveAveLevel(0), waveMinNoise(0), waveClipped(FALSE){}
	CTake(CTime& time, DWORD loc, int size, int totRaw, short center, short level, short noise, BOOL clipped) : recordTime(time), waveLoc(loc), waveSize(size), totalRaw(totRaw), thisWaveTakeLoc(0), nextWaveTakeLoc(0), waveCenter(center), waveAveLevel(level), waveMinNoise(noise), waveClipped(clipped){}
	CTake(CTake& orig) : recordTime(orig.recordTime), waveLoc(orig.waveLoc), waveSize(orig.waveSize), totalRaw(orig.totalRaw), thisWaveTakeLoc(orig.thisWaveTakeLoc), nextWaveTakeLoc(orig.nextWaveTakeLoc), waveCenter(orig.waveCenter), waveAveLevel(orig.waveAveLevel), waveMinNoise(orig.waveMinNoise), waveClipped(orig.waveClipped){}
	CTake& operator=(const CTake& rhs)
	{
		recordTime = rhs.recordTime; waveLoc = rhs.waveLoc; waveSize = rhs.waveSize; totalRaw = rhs.totalRaw; thisWaveTakeLoc = rhs.thisWaveTakeLoc; nextWaveTakeLoc = rhs.nextWaveTakeLoc; waveCenter = rhs.waveCenter; waveAveLevel = rhs.waveAveLevel; waveMinNoise = rhs.waveMinNoise; waveClipped = rhs.waveClipped;
		return *this;
	}
};

Open in new window

0
 
LVL 86

Expert Comment

by:jkr
ID: 35508115
Try to make that
CTake(const CTake& orig) : recordTime(orig.recordTime), waveLoc(orig.waveLoc), waveSize(orig.waveSize), totalRaw(orig.totalRaw), thisWaveTakeLoc(orig.thisWaveTakeLoc), nextWaveTakeLoc(orig.nextWaveTakeLoc), waveCenter(orig.waveCenter), waveAveLevel(orig.waveAveLevel), waveMinNoise(orig.waveMinNoise), waveClipped(orig.waveClipped){}

Open in new window

0
 

Author Comment

by:tantormedia
ID: 35508244
I could compile it, but unfortunately the problem is still there.
0
 
LVL 86

Expert Comment

by:jkr
ID: 35508283
Does this project consist just of an executable or are other modules involved (e.g. DLLs)? If so, are you adding elements in one module and destroying the vector in another?
0
 

Author Comment

by:tantormedia
ID: 35512148
No, everything is done in one module.
0
 

Author Comment

by:tantormedia
ID: 35512636
Here is the call stack in the debug mode:

       Book.exe!_CrtIsValidHeapPointer(const void * pUserData=0x0162d8a8)  Line 2103      C++
      Book.exe!_free_dbg_nolock(void * pUserData=0x0162d8a8, int nBlockUse=1)  Line 1317 + 0x9 bytes      C++
       Book.exe!_free_dbg(void * pUserData=0x0162d8a8, int nBlockUse=1)  Line 1258 + 0xd bytes      C++
       Book.exe!operator delete(void * p=0x0162d8a8)  Line 373 + 0xb bytes      C++
       Book.exe!std::allocator<CTake>::deallocate(CTake * _Ptr=0x0162d8a8, unsigned int __formal=3)  Line 140 + 0x9 bytes      C++
       Book.exe!std::vector<CTake,std::allocator<CTake> >::_Tidy()  Line 1134      C++
       Book.exe!std::vector<CTake,std::allocator<CTake> >::~vector<CTake,std::allocator<CTake> >()  Line 560      C++
       Book.exe!CParagraph::~CParagraph()  Line 231 + 0xfd bytes      C++


So _CrtIsValidHeapPointer() returns false, thus:
_ASSERTE(_CrtIsValidHeapPointer(pUserData)); fails.
0
 
LVL 35

Expert Comment

by:sarabande
ID: 35513745
those error may occur because of any other stack issue.. if for example you ever returned a pointer to a local variable and use that pointer in the calling function you may overwrite pointer values of the internal vector member. i also have seen such errors when a pointer to a local arrray was passed for use in a callback or in a asynchronously running thread. whenever the function where the local array
was defined runs out of scope the memory could be reused by any other function and such way destroy valid contents.

i would check all my functions which returm a pointer or which pass a pointer to other functions if that passing was valid. or use a purifier to check your code.

Sara



0
 

Author Comment

by:tantormedia
ID: 35513761
Thank you for your answer. What is purifier?
0
 
LVL 86

Expert Comment

by:jkr
ID: 35513778
Hm, what does the destructor of 'CParagraph' look like?
0
 

Author Comment

by:tantormedia
ID: 35513790
     ~CParagraph() { DeleteIf(m_pText); delete m_pImg; delete [] m_pNote; };
0
 

Author Comment

by:tantormedia
ID: 35513871
This is better:
      ~CParagraph() { delete [] m_pText; m_pText = NULL; delete m_pImg; delete [] m_pNote; m_pNote = NULL; };
0
 
LVL 86

Expert Comment

by:jkr
ID: 35513891
Could you add the declaration as well? Also, how are the pointers allocated?
0
 

Author Comment

by:tantormedia
ID: 35513999
This is the declaration. It is an inline function.
The data is read from file:
            int TextLen;
            cf->Read(&TextLen,sizeof(TextLen));

            pPara->m_pText = new char[TextLen+1];
            cf->Read(pPara->m_pText,TextLen);
            pPara->m_pText[TextLen]='\0';

                  int NoteLen;
                  cf->Read(&NoteLen, sizeof(NoteLen));

                  if(NoteLen > 0)
                  {
                        pPara->m_pNote = new char[NoteLen + 1];
                        cf->Read(pPara->m_pNote, NoteLen);
                        pPara->m_pNote[NoteLen] = '\0';
                  }

                  if(pPara->m_pImg != NULL)
                  {
                        delete(pPara->m_pImg);
                  }
                  cf->Seek(pPara->m_WaveLoc,CFile::begin);
                  char tp[4];
                  cf->Read(tp,4);
                  if(!strncmp(tp,"PNG ",4))
                  {
                        ULONGLONG s;
                        cf->Read(&s,sizeof(s));

                        CFile fTemp("temp.png", CFile::modeCreate|CFile::modeReadWrite);
                        ULONGLONG sizeWritten = 0;
                        while(s > 0)
                        {
                              ULONGLONG partSize = min(s, 1000000);
                              BYTE* pData = new BYTE[partSize];
                              cf->Read(pData, partSize);
                              fTemp.Seek(sizeWritten, CFile::begin);
                              fTemp.Write(pData, partSize);
                              delete [] pData;
                              s -= partSize;
                              sizeWritten += partSize;
                        }
                        fTemp.Close();

                        pPara->m_pImg = new CImage();
                        HRESULT res = pPara->m_pImg->Load("temp.png");
                  }

0
 
LVL 86

Expert Comment

by:jkr
ID: 35514055
Hm, OK, this is a little too complex apparently. When you debug the destructor of 'CParagraph' and examine 'm_vectorWaveTakes', does it still contain valid entries or does it seem to be overwritten with other data?
0
 

Author Comment

by:tantormedia
ID: 35514607
At least part of the data is invalid.
This part of code may be important:

                        CParagraph * pNewPara = new CParagraph();
                        memcpy(pNewPara,pPara,sizeof(CParagraph));
 ...
                        pNewPara->m_pText = NULL;
                        pNewPara->m_pImg = NULL;
                        pNewPara->m_pNote = NULL;
                        pNewPara->m_pMyChapter = NULL;
                        delete pNewPara;

Can deleting pNewPara corrupt a vector in pPara? It is *pPara that has the problem.
0
 
LVL 86

Accepted Solution

by:
jkr earned 2000 total points
ID: 35514670
The line

memcpy(pNewPara,pPara,sizeof(CParagraph));

seems to be the culprit. You simply can't do that with classes that hold more than POD data, and overwriting a 'vector' can definitely be the reason for the error you are seeing - better make that

*pNewPara = *pPara;

and provide an assignment operator if necessary.
0
 

Author Comment

by:tantormedia
ID: 35514703
I am getting an error:
error C2248: 'CObject::operator =' : cannot access private member declared in class 'CObject'
All members of CParagraph are public. What does it mean?
0
 
LVL 86

Expert Comment

by:jkr
ID: 35514721
Is 'CParagraph' derived from 'CObject'?
0
 

Author Comment

by:tantormedia
ID: 35514727
Yes
0
 
LVL 86

Expert Comment

by:jkr
ID: 35514840
Well, if it is necessary to keep that, you should give the assignment operator a try...
0
 

Author Closing Comment

by:tantormedia
ID: 35515309
Thank you very much. Problem is solved.
0
 
LVL 35

Expert Comment

by:sarabande
ID: 35698855
a purifier is a tool that checks your code. it would for eXAMPLE find out if you made new but never delete a pointer or whether you write outside of array boundaries. a good tool even may have found out the error with the memcpy.

the CObject::operator=  is made private to prevent you to make copies from CObject derived classes without supplying an explicit operator= for your class. for the same reason also the copy constructor of CObject is private.

see MSDN:

The standard C++ default class assignment behavior is a member-by-member copy. The presence of this private assignment operator guarantees a compiler error message if you assign without the overridden operator. You must therefore provide an assignment operator in your derived class if you intend to assign objects of your derived class.

So when you don't have a copy constructor or operator= for your class, the compiler tries to use the baseclass functionality which fails because those functions are private to class CObject.

Sara
0
 

Author Comment

by:tantormedia
ID: 35698907
Thank you Sara.
From your phrase "a good tool even may have found out the error with the memcpy" I make a conclusion that a purifier is not a certain tool, but a general name for tools of such kind. Maybe you could give me a specific name or place where I can get it, or maybe an example how it is used?
Thanks again.
0
 
LVL 35

Expert Comment

by:sarabande
ID: 35700456
the most known probably is Purify from Rational. also LINT from Gimpel is widely used. unfortunately i don't know free tools but surely there are some.l

Sara
0
 

Author Comment

by:tantormedia
ID: 35700471
Thank you very much.
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Errors will happen. It is a fact of life for the programmer. How and when errors are detected have a great impact on quality and cost of a product. It is better to detect errors at compile time, when possible and practical. Errors that make their wa…
Written by John Humphreys C++ Threading and the POSIX Library This article will cover the basic information that you need to know in order to make use of the POSIX threading library available for C and C++ on UNIX and most Linux systems.   [s…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.
Suggested Courses

862 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question