Bug 27530 - Possible memory leak in std::vector<int>::reserve() or std::vector<int>::clear()
Summary: Possible memory leak in std::vector<int>::reserve() or std::vector<int>::clear()
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 3.4.5
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-05-10 11:06 UTC by Konstantin Sharenkov
Modified: 2006-10-08 01:24 UTC (History)
3 users (show)

See Also:
Host: Intel Celeron 1.7G 768RAM Linux ( Fedora Core 2 )
Target: executable
Build: any compiler settings
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Konstantin Sharenkov 2006-05-10 11:06:38 UTC
Hello.

We have Client/server socket application (multiple clients and servers). Servers are multiplatform can be compiled for Windows (MSVC) and for Linux (GCC).
Recently we detected memory leak in one of kinde of our servers. At the start it uses only 15m (that is normally). Then it slowly grows up to 2000m within 2 weeks.
	Only Linux+GCC version was affected by this problem. We have checked our server by valgrind. It detected leak. The leak is possible in std::vectot<int>::reserve()or in std::vectot<int>::clear()

I use GCC 3.4.5 builded and installed on Fedora Core 2
REproduceable: Always.

The code producing leak:

...

typedef int card_type;
typedef int Funds;                                                      ….

const size_t MAX_CARDS_ON_HAND = 7;

typedef std::vector<card_type> CardsSet;
...

//----------------------------------------------------------------------------
class CBaseSeat : public ISerializable
{
public:
    CBaseSeat();
    void standUpSeat();
...
protected:
    unsigned m_flags;
    Funds m_cash;
    Funds m_bet;
    CardsSet m_cardsSet;
};

//----------------------------------------------------------------------------
CBaseSeat::CBaseSeat() 
:   m_flags(0),   m_cash(0),   m_bet(0),  m_cardsSet()
{
    m_cardsSet.reserve( MAX_CARDS_ON_HAND );
    standUpSeat();
}

//----------------------------------------------------------------------------
void CBaseSeat::standUpSeat()
{
    m_flags = 0;
    m_cash = 0;
    m_bet = 0;
    m_cardsSet.clear();
}


When we comment this line
//    m_cardsSet.reserve( MAX_CARDS_ON_HAND );

The leak is Gone. I just can suppose that the problem in reserve() or in clear() method whick called imediately after reserve();


Please see Valgrind report:  (after several minutes of work)

==22501== 124,376 bytes in 4,442 blocks are definitely lost in loss record 6 of 6
==22501==    at 0x43B8B10: operator new(unsigned) (vg_replace_malloc.c:164)
==22501==    by 0x806B2F9: __gnu_cxx::new_allocator<int>::allocate(unsigned, void const*) (new_allocator.h:81)
==22501==    by 0x806B191: std::_Vector_base<int, std::allocator<int> >::_M_allocate(unsigned) (stl_vector.h:113)
==22501==    by 0x807DD9C: int* std::vector<int, std::allocator<int> >::_M_allocate_and_copy<int*>(unsigned, int*, int*) (stl_vector.h:715)
==22501==    by 0x807DC96: std::vector<int, std::allocator<int> >::reserve(unsigned) (vector.tcc:78)
==22501==    by 0x80842E7: Poker::CBaseSeat::CBaseSeat() (seat.cpp:20)
==22501==    by 0x807123D: Poker::CClientSeat::CClientSeat(Poker::CClientSeat const&) (seat.h:134)
==22501==    by 0x80711FC: void std::_Construct<Poker::CClientSeat, Poker::CClientSeat>(Poker::CClientSeat*, Poker::CClientSeat const&) (stl_construct.h:81)
==22501==    by 0x8072FB8: __gnu_cxx::__normal_iterator<Poker::CClientSeat*, std::vector<Poker::CClientSeat, std::allocator<Poker::CClientSeat> > > std::__uninitialized_fill_n_aux<__gnu_cxx::__normal_iterator<Poker::CClientSeat*, std::vector<Poker::CClientSeat, std::allocator<Poker::CClientSeat> > >, unsigned, Poker::CClientSeat>(__gnu_cxx::__normal_iterator<Poker::CClientSeat*, std::vector<Poker::CClientSeat, std::allocator<Poker::CClientSeat> > >, unsigned, Poker::CClientSeat const&, __false_type) (stl_uninitialized.h:194)
==22501==    by 0x8072C5B: __gnu_cxx::__normal_iterator<Poker::CClientSeat*, std::vector<Poker::CClientSeat, std::allocator<Poker::CClientSeat> > > std::uninitialized_fill_n<__gnu_cxx::__normal_iterator<Poker::CClientSeat*, std::vector<Poker::CClientSeat, std::allocator<Poker::CClientSeat> > >, unsigned, Poker::CClientSeat>(__gnu_cxx::__normal_iterator<Poker::CClientSeat*, std::vector<Poker::CClientSeat, std::allocator<Poker::CClientSeat> > >, unsigned, Poker::CClientSeat const&) (stl_uninitialized.h:219)
==22501==    by 0x8072682: std::vector<Poker::CClientSeat, std::allocator<Poker::CClientSeat> >::_M_fill_insert(__gnu_cxx::__normal_iterator<Poker::CClientSeat*, std::vector<Poker::CClientSeat, std::allocator<Poker::CClientSeat> > >, unsigned, Poker::CClientSeat const&) (vector.tcc:314)
==22501==    by 0x8071CF3: std::vector<Poker::CClientSeat, std::allocator<Poker::CClientSeat> >::insert(__gnu_cxx::__normal_iterator<Poker::CClientSeat*, std::vector<Poker::CClientSeat, std::allocator<Poker::CClientSeat> > >, unsigned, Poker::CClientSeat const&) (stl_vector.h:612)
==22501==    by 0x8070CAC: std::vector<Poker::CClientSeat, std::allocator<Poker::CClientSeat> >::resize(unsigned, Poker::CClientSeat const&) (stl_vector.h:398)
==22501==    by 0x806FE22: std::vector<Poker::CClientSeat, std::allocator<Poker::CClientSeat> >::resize(unsigned) (stl_vector.h:412)
==22501==    by 0x806C0AB: Poker::CClientGameState::read(std::istream&) (clientgamestate.cpp:144)
==22501==    by 0x80B4430: Poker::CSelfHolder<Poker::CClientGameState>::read(std::istream&) (holder.h:147)
==22501==    by 0x808BE86: Poker::CMessage::read(std::istream&) (message.cpp:71)
==22501==    by 0x80A8D54: Poker::CMessageFactory::createFromStream(Poker::CSession*, std::istream&) (messagesfactory.cpp:1206)
==22501==    by 0x80E49F1: Poker::CRawDistiler::read(Poker::ISocket*, Poker::CServerSession*) (distiler.cpp:180)
==22501==    by 0x80E29E5: Poker::CConnection::recieveMessages() (connection.cpp:94)
==22501==    by 0x80E29A3: Poker::CConnection::doWork() (connection.cpp:81)
==22501==    by 0x80E6E49: Poker::CLobbyClient::doWork() (lobbyclient.cpp:123)
==22501==    by 0x80F827D: Poker::CBot::doWork() (bot.cpp:174)
==22501==    by 0x80FE742: Poker::CBotServer::doWork() (botserver.cpp:32)
==22501==    by 0x81028DB: main (main.cpp:35)


Hope my information will be usefull
Comment 1 Chris Jefferson 2006-05-10 11:31:33 UTC
Can you provide a complete program which demonstrates this link? I've tried looking at the code in question myself, and cannot observe a memory leak myself.
Comment 2 Paolo Carlini 2006-05-10 12:10:19 UTC
Chris is right. Certainly we are not aware of any problem in that code, in particular the 3.4.5 version, very close to the original HP/SGI code and very well tested from that point of view (at least). Please provide a self-contained testcase (as small as possible, of course), otherwise the PR, not really useful, likely will be soon closed, sorry.
Comment 3 Konstantin Sharenkov 2006-05-10 12:48:52 UTC
Ok, i will try to create a short program
Comment 4 Konstantin Sharenkov 2006-05-10 15:58:44 UTC
I have tried to create simple test case (about 200 rows) where I tried to reproduce key code fragments. In simple test case leak not reproduced. But I have easy reproduced it with very small application based on main project code.

Code like
        CMessage* m1 = theMessageFactory.createInstance( …)
        CMessage* m2 = m1->clone();
        delete m2;
        delete m1;


I am staring think that problem in templates instantiation. 

Also I already had problem with proper template instantiation in my Project. For some copy operations with vector of objects, vptr were set to 0 (caused SEG FAULT). I have not reported on It. I have resolved it by equal code but without copy operation.
(2 weeks spent to detect cause, I though I am was wrong somewhere &#61516; )

I have a test executable with full debug info (27M) (necessary libs statically linked)
Depends only 
ldd ./leaktest
        linux-gate.so.1 =>  (0x00f56000)
        libstdc++.so.6 => /usr/local/lib/libstdc++.so.6 (0x00111000)
        libm.so.6 => /lib/tls/libm.so.6 (0x0045c000)
        libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x005a5000)
        libc.so.6 => /lib/tls/libc.so.6 (0x00339000)
        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x00320000)


Will it be usefull for you? To analyze generated code.

Comment 5 Paolo Carlini 2006-05-15 16:58:13 UTC
(In reply to comment #4)
> I have tried to create simple test case (about 200 rows) where I tried to
> reproduce key code fragments. In simple test case leak not reproduced. But I
> have easy reproduced it with very small application based on main project code.

Please try harder to produce a self-contained, small, testcase. Otherwise, we cannot debug the issue. Thanks.
Comment 6 Chris Jefferson 2006-07-29 10:08:29 UTC
My natural suspision would be that your clone() function is incorrectly implemented. Can you show us the source to the CMessage object, and theMessageFactory.createInstance( …)?
Comment 7 Konstantin Sharenkov 2006-08-02 03:47:00 UTC
Hello.

Now I can say more about this problem. before code listing
I am sure that problem in template instantiation.
code if CBaseSeat::CBaseSeat() id used deeply in templates 
holder<T1> contains T1 which contains of vector<Derived from BaseSeat> which contains vector<int>

there are facts:
1) The leak was gone just i removed line    
m_cardsSet.reserve( MAX_CARDS_ON_HAND );
it was need only for allocatio optimize

2) Windows version of this code not affected by this problem

In any case i will try to create self contained test code when i will have a day for it. But it will be rather big i think.


There is the code:
//----------------------------------------------------------------------------------------
CMessage* CMessage::clone() const
{
    CMessage* result = new CMessage( m_descriptor, m_session, m_id );
    std::stringstream buffer;

    this->write( buffer );
    
    // read unnecessary type
    short type;
    shortSerializer.read( buffer, type );
    result->read( buffer );

    return result;
}

//----------------------------------------------------------------------------------------
CMessage* CMessageFactory::createInstance( CSession* sess, MessageType type )
{
    Descriptors::iterator pos = m_descriptors.find( type );
    if( pos==m_descriptors.end() )
    {
        throw std::logic_error("ERROR: Trying create message of unknown type" );
    }

    CMessage* result = new CMessage( pos->second, sess, nextMessageId() );

    return result;
}



Comment 8 Chris Jefferson 2006-08-03 19:48:48 UTC
One quick piece of advice. Have you tried compiling your entire application against the libstdc++ debug mode? It might help narrow down where the problem is.
Comment 9 Paolo Carlini 2006-10-08 01:24:35 UTC
Feedback not forthcoming.