Constructor ordering for memory pools vs. stdio

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Constructor ordering for memory pools vs. stdio

Wealand, Barry
Hello -

We're using eCos 2.0 with a MIPS-like target.  We're building eCos with
GCC 4.0.0 (in case that matters).  In an effort to locate a problem with
memory getting trashed, I built a couple of applications against a
kernel with assertions enabled.  Now, when these apps are executed, an
assertion failure occurs very quickly:

<5> stream.cxx[585] Cyg_ErrNo Cyg_StdioStream::write   Stream object is
not a valid stream!

Working backward from there, the problem comes about because
Cyg_StdioStream::initialize() does not finish and place the expected
value in "magic_validity_word".  Walking through the code with GDB, I
see that the constructor call, Cyg_StdioStream::Cyg_StdioStream(),
invokes a member constructor to set up an internal memory buffer.  This
constructor fails due to malloc() returning NULL.  On further
inspection, the memory pool upon which malloc depends has not yet been
set up.  And, indeed, looking at the constructor table in section
.ctors, and with the understanding that cyg_hal_invoke_constructors()
works through this table from higher memory addresses down to lower
memory addresses, it seems that the constructor call for the memory pool
comes later than the constructor call that sets up the stdio streams.  
And yet, I see (in malloc.cxx) that
CYGBLD_ATTRIB_INIT_BEFORE(CYG_INIT_LIBC) is being used to (seemingly)
specify that the memory pool constructor gets called before the libc
constructors (which presumably includes the stdio constructors).  On the
surface, anyway, this seems to be a contradiction.

Am I missing something here?  Should the memory pool constructor be
getting called before the stream constructor?

Thanks for your help!

Barry Wealand
[hidden email]



--
Before posting, please read the FAQ: http://ecos.sourceware.org/fom/ecos
and search the list archive: http://ecos.sourceware.org/ml/ecos-discuss

Reply | Threaded
Open this post in threaded view
|

Re: Constructor ordering for memory pools vs. stdio

Andrew Lunn-2
On Tue, Nov 08, 2005 at 02:15:22PM +0000, Barry Wealand wrote:

> Hello -
>
> We're using eCos 2.0 with a MIPS-like target.  We're building eCos with
> GCC 4.0.0 (in case that matters).  In an effort to locate a problem with
> memory getting trashed, I built a couple of applications against a
> kernel with assertions enabled.  Now, when these apps are executed, an
> assertion failure occurs very quickly:
>
> <5> stream.cxx[585] Cyg_ErrNo Cyg_StdioStream::write   Stream object is
> not a valid stream!
>
> Working backward from there, the problem comes about because
> Cyg_StdioStream::initialize() does not finish and place the expected
> value in "magic_validity_word".  Walking through the code with GDB, I
> see that the constructor call, Cyg_StdioStream::Cyg_StdioStream(),
> invokes a member constructor to set up an internal memory buffer.  This
> constructor fails due to malloc() returning NULL.  On further
> inspection, the memory pool upon which malloc depends has not yet been
> set up.  And, indeed, looking at the constructor table in section
> .ctors, and with the understanding that cyg_hal_invoke_constructors()
> works through this table from higher memory addresses down to lower
> memory addresses, it seems that the constructor call for the memory pool
> comes later than the constructor call that sets up the stdio streams.  
> And yet, I see (in malloc.cxx) that
> CYGBLD_ATTRIB_INIT_BEFORE(CYG_INIT_LIBC) is being used to (seemingly)
> specify that the memory pool constructor gets called before the libc
> constructors (which presumably includes the stdio constructors).  On the
> surface, anyway, this seems to be a contradiction.
>
> Am I missing something here?  Should the memory pool constructor be
> getting called before the stream constructor?

This sounds like a compiler problem:

(gdb) info br
Num Type           Disp Enb Address    What
1   breakpoint     keep y   0x01005c52 in Cyg_StdioStreamBuffer::set_buffer(unsigned int, unsigned char*)
                                       at /home/lunn/eCos/anoncvs-clean/packages/language/c/libc/stdio/current/src/common/streambuf.cxx:80
        breakpoint already hit 2 times
3   breakpoint     keep y   0x01008a36 in Cyg_Mempool_dlmalloc_Implementation
                                       at /home/lunn/eCos/anoncvs-clean/packages/services/memalloc/common/current/src/dlmalloc.cxx:950
        breakpoint already hit 2 times
4   breakpoint     keep y   0x01008907 in malloc at dlmalloc.hxx:133
        breakpoint already hit 1 time
(gdb)

(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/lunn/eCos/work/install/tests/language/c/libc/stdio/curre nt/tests/stdiooutput

Breakpoint 3, 0x01008a36 in Cyg_Mempool_dlmalloc_Implementation (
    this=0x200c800, base=0x200ccb0 "", size=8336208)
    at /home/lunn/eCos/anoncvs-clean/packages/services/memalloc/common/current/s rc/dlmalloc.cxx:950
950                                                 CYG_ADDRWORD /* argthru */ )

So first it calls the dlmalloc constructor.

(gdb) c
Continuing.

Breakpoint 1, Cyg_StdioStreamBuffer::set_buffer (this=0x200c78c, size=256,
    new_buffer=0x0)
    at /home/lunn/eCos/anoncvs-clean/packages/language/c/libc/stdio/current/src/common/streambuf.cxx:80
80          if (new_buffer != NULL) {

The set_buffer is called, which does:
(gdb) c
Continuing.

Breakpoint 4, malloc (size=256) at dlmalloc.hxx:133
133         try_alloc( cyg_int32 size ) { return mypool.try_alloc( size ); }

so everything is happening in the right order.

You might want to make a very simple test program with constructure
priorization which demonstrates the problem and then file a bug report
to the gcc people.

        Andrew

--
Before posting, please read the FAQ: http://ecos.sourceware.org/fom/ecos
and search the list archive: http://ecos.sourceware.org/ml/ecos-discuss

Reply | Threaded
Open this post in threaded view
|

Re: Constructor ordering for memory pools vs. stdio

Wealand, Barry


Barry Wealand wrote:

> Thank you, Andrew.  After doing a little more research this morning, I
> discovered that the problem was caused by the ecos-2.0 version of
> packages/services/memalloc/common/v2_0/src/heapgen.tcl, which was
> generating C++ source with incorrect placement of the
> CYGBLD_ATTRIB_INIT_PRI(...) macro.  This problem was specifically
> addressed and fixed with rev. 1.9 of this file.  After replacing this
> file in our eCos source tree and rebuilding from scratch, all of these
> problems have gone away.
>
> Thanks again for your support.
>
> Barry Wealand
>
>
> Andrew Lunn wrote:
>
>>On Tue, Nov 08, 2005 at 02:15:22PM +0000, Barry Wealand wrote:
>>  
>>
>>>Hello -
>>>
>>>We're using eCos 2.0 with a MIPS-like target.  We're building eCos with
>>>GCC 4.0.0 (in case that matters).  In an effort to locate a problem with
>>>memory getting trashed, I built a couple of applications against a
>>>kernel with assertions enabled.  Now, when these apps are executed, an
>>>assertion failure occurs very quickly:
>>>
>>><5> stream.cxx[585] Cyg_ErrNo Cyg_StdioStream::write   Stream object is
>>>not a valid stream!
>>>
>>>Working backward from there, the problem comes about because
>>>Cyg_StdioStream::initialize() does not finish and place the expected
>>>value in "magic_validity_word".  Walking through the code with GDB, I
>>>see that the constructor call, Cyg_StdioStream::Cyg_StdioStream(),
>>>invokes a member constructor to set up an internal memory buffer.  This
>>>constructor fails due to malloc() returning NULL.  On further
>>>inspection, the memory pool upon which malloc depends has not yet been
>>>set up.  And, indeed, looking at the constructor table in section
>>>.ctors, and with the understanding that cyg_hal_invoke_constructors()
>>>works through this table from higher memory addresses down to lower
>>>memory addresses, it seems that the constructor call for the memory pool
>>>comes later than the constructor call that sets up the stdio streams.  
>>>And yet, I see (in malloc.cxx) that
>>>CYGBLD_ATTRIB_INIT_BEFORE(CYG_INIT_LIBC) is being used to (seemingly)
>>>specify that the memory pool constructor gets called before the libc
>>>constructors (which presumably includes the stdio constructors).  On the
>>>surface, anyway, this seems to be a contradiction.
>>>
>>>Am I missing something here?  Should the memory pool constructor be
>>>getting called before the stream constructor?
>>>    
>>>
>>
>>This sounds like a compiler problem:
>>
>>(gdb) info br
>>Num Type           Disp Enb Address    What
>>1   breakpoint     keep y   0x01005c52 in Cyg_StdioStreamBuffer::set_buffer(unsigned int, unsigned char*)
>>                                       at /home/lunn/eCos/anoncvs-clean/packages/language/c/libc/stdio/current/src/common/streambuf.cxx:80
>>        breakpoint already hit 2 times
>>3   breakpoint     keep y   0x01008a36 in Cyg_Mempool_dlmalloc_Implementation
>>                                       at /home/lunn/eCos/anoncvs-clean/packages/services/memalloc/common/current/src/dlmalloc.cxx:950
>>        breakpoint already hit 2 times
>>4   breakpoint     keep y   0x01008907 in malloc at dlmalloc.hxx:133
>>        breakpoint already hit 1 time
>>(gdb)
>>
>>(gdb) run
>>The program being debugged has been started already.
>>Start it from the beginning? (y or n) y
>>
>>Starting program: /home/lunn/eCos/work/install/tests/language/c/libc/stdio/curre nt/tests/stdiooutput
>>
>>Breakpoint 3, 0x01008a36 in Cyg_Mempool_dlmalloc_Implementation (
>>    this=0x200c800, base=0x200ccb0 "", size=8336208)
>>    at /home/lunn/eCos/anoncvs-clean/packages/services/memalloc/common/current/s rc/dlmalloc.cxx:950
>>950                                                 CYG_ADDRWORD /* argthru */ )
>>
>>So first it calls the dlmalloc constructor.
>>
>>(gdb) c
>>Continuing.
>>
>>Breakpoint 1, Cyg_StdioStreamBuffer::set_buffer (this=0x200c78c, size=256,
>>    new_buffer=0x0)
>>    at /home/lunn/eCos/anoncvs-clean/packages/language/c/libc/stdio/current/src/common/streambuf.cxx:80
>>80          if (new_buffer != NULL) {
>>
>>The set_buffer is called, which does:
>>(gdb) c
>>Continuing.
>>
>>Breakpoint 4, malloc (size=256) at dlmalloc.hxx:133
>>133         try_alloc( cyg_int32 size ) { return mypool.try_alloc( size ); }
>>
>>so everything is happening in the right order.
>>
>>You might want to make a very simple test program with constructure
>>priorization which demonstrates the problem and then file a bug report
>>to the gcc people.
>>
>>        Andrew
>>
>>  
>>


--
Before posting, please read the FAQ: http://ecos.sourceware.org/fom/ecos
and search the list archive: http://ecos.sourceware.org/ml/ecos-discuss