"free(): invalid next size" when using std::map as a class member

C

Chuck Chopp

Included here is a very simple class declaration. When this declaration
is placed in its own header file [test.hpp] and the class member
function definitions are placed in their own file [test.cpp], then the
simple usage case that follows results in a SIGABRT when built with GCC
v4.12 on SUSE Linux Enterprise Server v10.0 SP1.


header file "test.hpp":

#include <map>

class CTest01
{
public:

CTest01();

CTest01(const CTest01& X);

~CTest01();

CTest01& operator=(const CTest01& X);

protected:

private:

std::map<int, int> m_Map;

};


code module "test.cpp":

CTest01::CTest01()
:
m_Map()
{
return;
}


CTest01::CTest01(const CTest01&)
:
m_Map()
{
return;
}


CTest01::~CTest01()
{
return;
}


CTest01& CTest01::eek:perator=(const CTest01&)
{
return (*this);
}


test case that uses CTest01:

#include "test.hpp"

int main(int argc, char* argv[])
{
CTest01 *pTest = NULL;

pTest = new CTest01();

if (NULL != pTest)
{
delete pTest;
}

return 0;
}



Building this as a console application on Windows Vista using Visual
C/C++ v9.0 [Visual Studio 2008] results in a binary that executes w/o
any faults.

Building this on SUSE Linux Enterprise Server v10.0 SP1 using GCC v4.12,
I get a clean compilation but a SIGABRT at run time.

"*** glibc detected *** ./x86_64/test: free(): invalid next size (fast):
0x0000000000588240 ***

followed by a back trace that I'll omit for now.


The problem occurs in the same way for both 32-bit and 64-bit builds,
running on i386 or x86_64 builds of SLES 10.


I'm not entirely certain if I'm dealing with a problem with GCC, a
problem with the glibc implementation on SLES 10 or if I'm missing some
subtle detail related to using std::map as a data member in another
class. So, I'm starting here and if it's necessary to take this to a
more appropriate newsgroup, I'll repost elsewhere as-needed.

Interestingly enough, if I combine the declaration & definition of
CTest01 and it's members directly into the file scope of the code that
makes use of CTest01, then the problem goes away. It's only when the
definition is in an external file that this problem occurs.

Using an std::list class object as a class data member in CTest01 does
not result in this problem occurring. It's only when I use a std::map
class object as a data member in CTest01 that this problem occurs.
Also, it makes no difference what values I use for the template
instantiation of std::map, as the problem happens with <int, int>,
<inst, std::string> and even <std::string, int>, etc....


Any ideas or thoughts as to what might be causing this?
 
S

Salt_Peter

Included here is a very simple class declaration. When this declaration
is placed in its own header file [test.hpp] and the class member
function definitions are placed in their own file [test.cpp], then the
simple usage case that follows results in a SIGABRT when built with GCC
v4.12 on SUSE Linux Enterprise Server v10.0 SP1.

header file "test.hpp":

#include <map>

class CTest01
{
public:

CTest01();

CTest01(const CTest01& X);

~CTest01();

CTest01& operator=(const CTest01& X);

protected:

private:

std::map<int, int> m_Map;

};

code module "test.cpp":

#include "test.hpp"
CTest01::CTest01()
:
m_Map()
{
return;

remove the return statement
}

CTest01::CTest01(const CTest01&)
:
m_Map()

CTest01::CTest01(const CTest01& cpy)
: m_Map(cpy.m_Map)
{
return;

remove the return statement.
}

CTest01::~CTest01()
{
return;

remove it
}

CTest01& CTest01::eek:perator=(const CTest01&)
{
return (*this);

// self assignment check
if( this == &rhv ) return *this;
// assign
m_Map = rhv.m_Map;
return *this;
}

test case that uses CTest01:

#include "test.hpp"

int main(int argc, char* argv[])
{
CTest01 *pTest = NULL;

pTest01 = new CTest01();
pTest = new CTest01;

Why allocate on the heap at all?

CTest01 instance;

Only use the heap when absolutely needed.
Even then there are better solutions.
if (NULL != pTest)
{
delete pTest;
}

return 0;

}

Building this as a console application on Windows Vista using Visual
C/C++ v9.0 [Visual Studio 2008] results in a binary that executes w/o
any faults.

Building this on SUSE Linux Enterprise Server v10.0 SP1 using GCC v4.12,
I get a clean compilation but a SIGABRT at run time.

"*** glibc detected *** ./x86_64/test: free(): invalid next size (fast):
0x0000000000588240 ***

followed by a back trace that I'll omit for now.

The problem occurs in the same way for both 32-bit and 64-bit builds,
running on i386 or x86_64 builds of SLES 10.

I'm not entirely certain if I'm dealing with a problem with GCC, a
problem with the glibc implementation on SLES 10 or if I'm missing some
subtle detail related to using std::map as a data member in another
class. So, I'm starting here and if it's necessary to take this to a
more appropriate newsgroup, I'll repost elsewhere as-needed.

Interestingly enough, if I combine the declaration & definition of
CTest01 and it's members directly into the file scope of the code that
makes use of CTest01, then the problem goes away. It's only when the
definition is in an external file that this problem occurs.

Using an std::list class object as a class data member in CTest01 does
not result in this problem occurring. It's only when I use a std::map
class object as a data member in CTest01 that this problem occurs.
Also, it makes no difference what values I use for the template
instantiation of std::map, as the problem happens with <int, int>,
<inst, std::string> and even <std::string, int>, etc....

Any ideas or thoughts as to what might be causing this?

free(): invalid next size (fast):

The above error is usually indicative of a corrupted stack or heap.
The code shown is not the problem as far as i can tell.
 
J

James Kanze

Included here is a very simple class declaration. When this
declaration is placed in its own header file [test.hpp] and
the class member function definitions are placed in their own
file [test.cpp], then the simple usage case that follows
results in a SIGABRT when built with GCC v4.12 on SUSE Linux
Enterprise Server v10.0 SP1.

[...]
Building this on SUSE Linux Enterprise Server v10.0 SP1 using
GCC v4.12, I get a clean compilation but a SIGABRT at run
time.
"*** glibc detected *** ./x86_64/test: free(): invalid next size (fast):
0x0000000000588240 ***
followed by a back trace that I'll omit for now.
The problem occurs in the same way for both 32-bit and 64-bit
builds, running on i386 or x86_64 builds of SLES 10.

What options did you use for the compile? If you really do have
problems with the posted code, and it works when you compile
everything in one module, I would susect different compiler
options when compiling the two modules.
 
T

Triple-DES

     // self assignment check
     if( this == &rhv ) return *this;
     // assign
     m_Map = rhv.m_Map;
     return *this;

Note that you have altered the semantics of the assignment operator
with your correction. If the intention was to have normal assignment
semantics for this class, the better solution would be to simply use
the implicitly generated assignment operator.

In any case the self-assignment check is redundant.
 
C

Chuck Chopp

OK, posting back to myself but in reply to Salt_Peter, Triple-DES and
James Kanze, trying to keep this from fragmenting all over the place.


1) Heap vs. Stack allocation. The intent is not to be allocating these
objects from the heap. The problem was found in a much more complex
class, and "CTest01" was simply what I was left when when I had isolated
the code that was causing the problem. I get this SIGABRT failure and
"free()..." message from glibc during object construction for CTest01
regardless of whether I create the object on the stack or on the heap.
It was first caught in gdb when a stack-based instance was being
created, but the problem can be easily demonstrated when creating the
object on the heap, too.


2) I don't care about the copy constructor or the copy operator
overloads. They aren't pertinent to the discussion of this problem and
so they only exist with sufficient definition that they compile and and
gcc's effective C++ warnings don't complain about the missing methods.
In no place in the test case scenario will you see them used and they
aren't intended to be used.


3) Both the main.cpp and test.cpp modules were built with the same
compiler settings in the same makefile, and were linked together by the
same makefile.

The compiler flags are as follows:

-std=c++98 -pthread -Wall -Weffc++ -g3 -O0

with either of "-m32" or "-m64" added to specify the target architecture.

The linker flags are as follows:

-pthread



I agree, the behavior appears to be stack corruption, and nothing would
intuitively indicate that simply instantiating an object of this class
type would cause this problem, or would otherwise make a previously
hidden stack corruption problem visible. However, this only happens
when I use an instance of std::map as a data member in the class, and it
happens in every other class I have that contains a data member of type
std::map.

If I replace with an std::list object type, the problem goes away.

If I change the data member from an object instance of type std::map to
a pointer to std::map, and then allocate "new std::map<int, int>();" in
the class constructor and deallocate with "delete m_pMap;" in the
destructor, the problem goes away.

It's only when the class object contains an instance of std::map that
the problem occurs, and only when building with gcc on SLES 10.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top