malloc_g misunderstanding

Hi,
I have 2 questions about malloc_g functions.

Because of a bug in my application, I had to use malloc_g library to
track a memory leakage, and I didn’t really understand the result.
My application is a multithreaded resource manager.

I choosed to write the malloc_dump_unreferenced(1, 1) in my
xxx_ocb_free() function.

In my main(), I allocate the thread pool atribute structure, pointed by
a global pointer. Like that:

#ifdef NDEBUG
if ((pool_attr_p = calloc(1, sizeof(thread_pool_attr_t))) == NULL) {

#else
if ((pool_attr_p = debug_calloc(basename(FILE), LINE, 1,
sizeof(thread_pool_attr_t))) == NULL) {
#endif

As I understood, the malloc_g library gives the unreachables memory
area, so why does it give me the memory area pointed by pool_attr_p , a
global pointer, (I verified that this pointer was still good when
malloc_dump_unreferenced() was executed)?

POINTER FILE WHERE LINE ALLOC DATA HEX
DUMP
TO DATA ALLOCATED NUMBER FUNCT LENGTH OF BYTES
1-7




804F494 fct_nto.c 27 calloc(1) 68 …

What is the number between parenthesis?

My bug was in the following function:

int read_record(record_buffer_t *record_buffer_ptr, data_hash_t
*data_hash) {
int return_value = 0;
char *buffer_read;

#ifdef NDEBUG
buffer_read = malloc(data_hash->record_len+1);
#else
buffer_read = debug_malloc(basename(FILE), LINE,
data_hash->record_len+1);
#endif

if ((status = readblock(fd_database, (size_t) 1,
data_hash->record_offset, data_hash->record_len, buffer_read)) == -1) {
return_value = errno;
log_critical_error("%s, %s, %d: (readblock) %s
%s\n",basename(FILE),LINE, “”, errno);
} else {
buffer_read[data_hash->record_len] = ‘\0’;
split_database_record(&buffer_read_ptr, record_buffer);
}

#ifdef NDEBUG
free(buffer_read);
#else
debug_free(basename(FILE), LINE, buffer_read);
#endif

return (return_value);
}

I didn’t take care about that the function split_database_record()
returned a null pointer.
So, free() couldn’t give the buffer back to the heap.
My question is; as the buffer is allocated by a malloc_g function with
the FILE and LINE macros, why these informations were not given
in the Dump of Unreferenced Heap elements?

Thanks,
Alain.

In article <3A7A655A.45700EA3@icbt.com>,
Alain Bonnefoy <alain.bonnefoy@icbt.com> wrote:

--------------F333DCF7D4B324C705DDCA44
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Hi,
I have 2 questions about malloc_g functions.

Because of a bug in my application, I had to use malloc_g library to
track a memory leakage, and I didn’t really understand the result.
My application is a multithreaded resource manager.

I choosed to write the malloc_dump_unreferenced(1, 1) in my
xxx_ocb_free() function.

In my main(), I allocate the thread pool atribute structure, pointed by
a global pointer. Like that:

#ifdef NDEBUG
if ((pool_attr_p = calloc(1, sizeof(thread_pool_attr_t))) == NULL) {

#else
if ((pool_attr_p = debug_calloc(basename(FILE), LINE, 1,
sizeof(thread_pool_attr_t))) == NULL) {
#endif

As I understood, the malloc_g library gives the unreachables memory
area, so why does it give me the memory area pointed by pool_attr_p , a
global pointer, (I verified that this pointer was still good when
malloc_dump_unreferenced() was executed)?

It’s important to remember that, because of raw pointer access and
the like of compiler assistance, a 100% accurate leak trace isn’t really
possible, so an analysis of the heap dump is recommended. Conservative
pointer estimation is used to ameliorate the effects of inner pointers
and pointers contained in structures.

Before going further, did pool_attr_p actually point to 0x804f494
at the time?

The major thing that would impact your example is the construction of the
root set (since everything must be reachable from the root set).
The determination of the root set is complicated by several factors,
and a situation like this would depend on where pool_attr_p was defined.
Was it a global (extern) or a static variable? Perhaps more importantly,
was it in the executable or a shared library?

To construct the root set, malloc_g consults the dynamic link map
to find all the libraries linked against and looks for the extents
of the _data and _bss sections. After that it adds all the thread stacks.

If yours is in the executable that may explain something, if
the executable itself isn’t included in the link map. Please let me
know.

POINTER FILE WHERE LINE ALLOC DATA HEX
DUMP
TO DATA ALLOCATED NUMBER FUNCT LENGTH OF BYTES
1-7




804F494 fct_nto.c 27 calloc(1) 68 …

What is the number between parenthesis?

That is a sequence number for allocation requests, indicating which
occurrence of the particular function the request was. i.e. this
was the first calloc() request.

My bug was in the following function:

int read_record(record_buffer_t *record_buffer_ptr, data_hash_t
*data_hash) {
int return_value = 0;
char *buffer_read;

#ifdef NDEBUG
buffer_read = malloc(data_hash->record_len+1);
#else
buffer_read = debug_malloc(basename(FILE), LINE,
data_hash->record_len+1);
#endif

if ((status = readblock(fd_database, (size_t) 1,
data_hash->record_offset, data_hash->record_len, buffer_read)) == -1) {
return_value = errno;
log_critical_error("%s, %s, %d: (readblock) %s
%s\n",basename(FILE),LINE, “”, errno);
} else {
buffer_read[data_hash->record_len] = ‘\0’;
split_database_record(&buffer_read_ptr, record_buffer);
}

#ifdef NDEBUG
free(buffer_read);
#else
debug_free(basename(FILE), LINE, buffer_read);
#endif

return (return_value);
}

I didn’t take care about that the function split_database_record()
returned a null pointer.
So, free() couldn’t give the buffer back to the heap.
My question is; as the buffer is allocated by a malloc_g function with
the FILE and LINE macros, why these informations were not given
in the Dump of Unreferenced Heap elements?

I may be missing something, but I didn’t see any indication of
what was printed in the dump. The file and line information
is kept in the block header after the allocation and isn’t cleared
except by a call to realloc() or free(), unless the program underruns
the block, corrupting the header, or overruns a neighbouring block.

Thanks,
Alain.

--------------F333DCF7D4B324C705DDCA44
Content-Type: text/html; charset=us-ascii
Content-Transfer-Encoding: 7bit

!doctype html public “-//w3c//dtd html 4.0 transitional//en”
html
font face=“Arial,Helvetica”>Hi,</font
br>I have 2 questions about
malloc_g functions.</font
p>Because of a bug in my application,
I had to use malloc_g library to track a memory leakage, and I didn’t really
understand the result.</font
br>My application is a multithreaded
resource manager.</font
p>I choosed to write the malloc_dump_unreferenced(1,

  1. in my xxx_ocb_free() function.</font
    p>In my main(), I allocate
    the thread pool atribute structure, pointed by a global pointer. Like that:</font
    p>#ifdef NDEBUG</font
    br>    if
    ((pool_attr_p = calloc(1, sizeof(thread_pool_attr_t))) == NULL) {</font
    br>#else</font
    br>    if
    ((pool_attr_p = debug_calloc(basename(FILE), LINE, 1, sizeof(thread_pool_attr_t)))
    == NULL) {</font
    br>#endif</font
    p>As I understood, the malloc_g
    library gives the unreachables memory area, so why does it give me the
    memory area pointed by pool_attr_p , a global pointer, (I verified that
    this pointer was still good when malloc_dump_unreferenced() was executed)?</font
    p>POINTER       
    FILE WHERE    LINE      ALLOC        
    DATA        HEX DUMP</font
    br>TO DATA       
    ALLOCATED    NUMBER     FUNCT       
    LENGTH    OF BYTES 1-7</font
    br>---------- ---------------
    -------- ------------ ----------- ---------------</font
    br>…</font
    br>804F494   
    fct_nto.c            
    27 calloc(1)            
    68 …</font
    br>…</font
    p>What is the number between
    parenthesis?</font
    p>My bug was in the following
    function:</font
    p>int read_record(record_buffer_t
    *record_buffer_ptr,  data_hash_t *data_hash) {</font
    br>  int return_value
    = 0;</font
    br>  char *buffer_read;</font
    br> </font
    br>#ifdef NDEBUG</font
    br>  buffer_read =
    malloc(data_hash->record_len+1);</font
    br>#else</font
    br>  buffer_read =
    debug_malloc(basename(FILE), LINE, data_hash->record_len+1);</font
    br>#endif</font
    br> </font
    br>  if ((status =
    readblock(fd_database, (size_t) 1, data_hash->record_offset, data_hash->record_len,
    buffer_read)) == -1) {</font
    br>    return_value
    = errno;</font
    br>    log_critical_error("%s,
    %s, %d: (readblock) %s %s\n",basename(FILE),LINE, “”, errno);</font
    br>  } else {</font
    br>    buffer_read[data_hash->record_len]
    = ‘\0’;</font
    br>    split_database_record(&buffer_read_ptr,
    record_buffer);</font
    br>  }</font
    br> </font
    br>#ifdef NDEBUG</font
    br>  free(buffer_read);</font
    br>#else</font
    br>  debug_free(basename(FILE),
    LINE, buffer_read);</font
    br>#endif</font
    br> </font
    br>  return (return_value);</font
    br>}</font
    p>I didn’t take care about
    that the function split_database_record() returned a null pointer.</font
    br>So, free() couldn’t give
    the buffer back to the heap.</font
    br>My question is; as the buffer
    is allocated by a malloc_g function with the FILE and LINE macros,
    why these informations were not given in the Dump of Unreferenced Heap
    elements?</font
    p>Thanks,</font
    br>Alain.</html

--------------F333DCF7D4B324C705DDCA44–

Steve Furr email: furr@qnx.com
QNX Software Systems, Ltd.

Steve Furr a écrit :

In article <> 3A7A655A.45700EA3@icbt.com> >,
Alain Bonnefoy <> alain.bonnefoy@icbt.com> > wrote:

--------------F333DCF7D4B324C705DDCA44
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Hi,
I have 2 questions about malloc_g functions.

Because of a bug in my application, I had to use malloc_g library to
track a memory leakage, and I didn’t really understand the result.
My application is a multithreaded resource manager.

I choosed to write the malloc_dump_unreferenced(1, 1) in my
xxx_ocb_free() function.

In my main(), I allocate the thread pool atribute structure, pointed by
a global pointer. Like that:

#ifdef NDEBUG
if ((pool_attr_p = calloc(1, sizeof(thread_pool_attr_t))) == NULL) {

#else
if ((pool_attr_p = debug_calloc(basename(FILE), LINE, 1,
sizeof(thread_pool_attr_t))) == NULL) {
#endif

As I understood, the malloc_g library gives the unreachables memory
area, so why does it give me the memory area pointed by pool_attr_p , a
global pointer, (I verified that this pointer was still good when
malloc_dump_unreferenced() was executed)?

It’s important to remember that, because of raw pointer access and
the like of compiler assistance, a 100% accurate leak trace isn’t really
possible, so an analysis of the heap dump is recommended. Conservative
pointer estimation is used to ameliorate the effects of inner pointers
and pointers contained in structures.

Before going further, did pool_attr_p actually point to 0x804f494
at the time?

Yes, pool_attr_p points to 0x804f494 from its allocation and still points to this address when I call malloc_dump_unreferenced().
It’s strange that malloc_g kept the information about who made the allocation but loose the information about this pointer still exists.

The major thing that would impact your example is the construction of the
root set (since everything must be reachable from the root set).
The determination of the root set is complicated by several factors,
and a situation like this would depend on where pool_attr_p was defined.
Was it a global (extern) or a static variable?

it’s a global variable

Perhaps more importantly,
was it in the executable or a shared library?

Yes it’s allocated by a malloc_g in a function called main() and I call malloc_dump_unreferenced in thread created by a pool.

To construct the root set, malloc_g consults the dynamic link map
to find all the libraries linked against and looks for the extents
of the _data and _bss sections. After that it adds all the thread stacks.

If yours is in the executable that may explain something, if
the executable itself isn’t included in the link map. Please let me
know.

What do you want I verify exactly?

POINTER FILE WHERE LINE ALLOC DATA HEX
DUMP
TO DATA ALLOCATED NUMBER FUNCT LENGTH OF BYTES
1-7




804F494 fct_nto.c 27 calloc(1) 68 …

What is the number between parenthesis?

That is a sequence number for allocation requests, indicating which
occurrence of the particular function the request was. i.e. this
was the first calloc() request.


My bug was in the following function:

int read_record(record_buffer_t *record_buffer_ptr, data_hash_t
*data_hash) {
int return_value = 0;
char *buffer_read;

#ifdef NDEBUG
buffer_read = malloc(data_hash->record_len+1);
#else
buffer_read = debug_malloc(basename(FILE), LINE,
data_hash->record_len+1);
#endif

if ((status = readblock(fd_database, (size_t) 1,
data_hash->record_offset, data_hash->record_len, buffer_read)) == -1) {
return_value = errno;
log_critical_error("%s, %s, %d: (readblock) %s
%s\n",basename(FILE),LINE, “”, errno);
} else {
buffer_read[data_hash->record_len] = ‘\0’;
split_database_record(&buffer_read_ptr, record_buffer);
}

#ifdef NDEBUG
free(buffer_read);
#else
debug_free(basename(FILE), LINE, buffer_read);
#endif

return (return_value);
}

I didn’t take care about that the function split_database_record()
returned a null pointer.
So, free() couldn’t give the buffer back to the heap.
My question is; as the buffer is allocated by a malloc_g function with
the FILE and LINE macros, why these informations were not given
in the Dump of Unreferenced Heap elements?

I may be missing something, but I didn’t see any indication of
what was printed in the dump. The file and line information
is kept in the block header after the allocation and isn’t cleared
except by a call to realloc() or free(), unless the program underruns
the block, corrupting the header, or overruns a neighbouring block.

Yes, you’re right, the complete dump is:

Dump of Unreferenced Heap Elements
************************ Dump of Leaked Heap Memory *************************


ARENA 804f000, size 16384:

POINTER FILE WHERE LINE ALLOC DATA HEX DUMP
TO DATA ALLOCATED NUMBER FUNCT LENGTH OF BYTES 1-7


804F040 B031D23E malloc(1) 512 40414243444546
804F634 804C189 malloc(117) 67 3435363738393A
804FA5C 804C189 malloc(87) 65 5C5D5E5F606162
804FACC 804C189 malloc(72) 67 CCCDCECFD0D1D2
804FB3C 804C189 malloc(67) 67 3C3D3E3F404142
805140C B0324363 malloc(24) 92 0C0D0E0F101112
8051494 fct_nto.c 28 calloc(1) 68 9495969798999A
805272C B032B412 malloc(9) 84 2C2D2E2F303132
80527AC B032B412 malloc(6) 84 ACADAEAFB0B1B2
8052FA4 B032B412 malloc(2) 84 A4A5A6A7A8A9AA


10 Leaked entries 1196 bytes


ARENA 8057000, size 16384:

POINTER FILE WHERE LINE ALLOC DATA HEX DUMP
TO DATA ALLOCATED NUMBER FUNCT LENGTH OF BYTES 1-7


8057040 FEED0018 malloc(143) 1612 40414243444546
8057850 FEED0030 malloc(649) 1484 50515253545556
8057E48 804C189 malloc(358) 68 48494A4B4C4D4E
8057EB8 804C189 malloc(354) 68 B8B9BABBBCBDBE
80585A0 804C189 malloc(349) 66 A0A1A2A3A4A5A6
8058610 804C189 malloc(345) 69 10111213141516
8058684 804C189 malloc(336) 67 8485868788898A
8058DEC 804C189 malloc(306) 68 ECEDEEEFF0F1F2
8059C44 804C189 malloc(244) 256 4445464748494A
8059D70 804C189 malloc(242) 256 70717273747576
8059E9C 804C189 malloc(217) 65 9C9D9E9FA0A1A2
8059F0C 804C189 malloc(213) 65 0C0D0E0F101112


12 Leaked entries 4156 bytes


ARENA 805b000, size 16384:

POINTER FILE WHERE LINE ALLOC DATA HEX DUMP
TO DATA ALLOCATED NUMBER FUNCT LENGTH OF BYTES 1-7


805B040 FEED0028 malloc(391) 1996 40414243444546
805B8F8 FEED0030 malloc(1090) 1484 F8F9FAFBFCFDFE
805C10C FEED0030 malloc(1212) 1484 0C0D0E0F101112
805C798 FEED0030 malloc(701) 1484 98999A9B9C9D9E
805CE24 FEED0030 malloc(599) 1484 2425262728292A
805D41C B033902C malloc(433) 1024 1C1D1E1F202122
805D9EC B0337552 realloc(9) 224 ECEDEEEFF0F1F2
805DAF8 FEED0030 malloc(485) 1484 F8F9FAFBFCFDFE
805E3A0 FEED0030 malloc(543) 1484 A0A1A2A3A4A5A6
805EA2C FEED0030 malloc(408) 1484 2C2D2E2F303132


10 Leaked entries 13632 bytes


ARENA 805f000, size 16384:

POINTER FILE WHERE LINE ALLOC DATA HEX DUMP
TO DATA ALLOCATED NUMBER FUNCT LENGTH OF BYTES 1-7


805F7C0 FEED0030 malloc(1149) 1484 C0C1C2C3C4C5C6
805FE4C FEED0030 malloc(1028) 1484 4C4D4E4F505152
80605CC FEED0030 malloc(1276) 1484 CCCDCECFD0D1D2
8060CEC FEED0030 malloc(969) 1484 ECEDEEEFF0F1F2
80612E4 FEED0030 malloc(861) 1484 E4E5E6E7E8E9EA
80618DC FEED0030 malloc(753) 1484 DCDDDEDFE0E1E2
8062434 FEED0030 malloc(915) 1484 3435363738393A
8062A2C FEED0030 malloc(807) 1484 2C2D2E2F303132


8 Leaked entries 11872 bytes


ARENA 8063000, size 16384:

POINTER FILE WHERE LINE ALLOC DATA HEX DUMP
TO DATA ALLOCATED NUMBER FUNCT LENGTH OF BYTES 1-7


8064A3C FEED0030 malloc(1458) 1484 3C3D3E3F404142
8065034 B03228F4 malloc(1405) 2169 3435363738393A
80658DC B03228F4 malloc(1470) 2169 DCDDDEDFE0E1E2
8066184 FEED0030 malloc(1345) 1484 8485868788898A
8066998 io_funcs.c 28 calloc(292) 104 98999A9B9C9D9E
8066A2C FEED0030 malloc(1408) 1484 2C2D2E2F303132


6 Leaked entries 8900 bytes


BAND b035c280, small buffer size 8:



BAND b035c28c, small buffer size 12:



BAND b035c298, small buffer size 16:



BAND b035c2a4, small buffer size 24:



BAND b035c2b0, small buffer size 32:



BAND b035c2bc, small buffer size 40:



BAND b035c2c8, small buffer size 48:



BAND b035c2d4, small buffer size 64:


The bug we are talking about causes memory allocation (and not freed) at adresses 0xFEED0030 (I think, compare to execution without bug).
Maybe the problem is caused by the fact that free() is called by a null pointer. So, free clear the header and all necessary informations to find the bug!!

If so, could you make something to prevent this problem?

Thanks,
Alain.

In article <3A8114F0.84D504A4@icbt.com>,
Alain Bonnefoy <alain.bonnefoy@icbt.com> wrote:

Steve Furr a écrit :

[snip]



Yes, pool_attr_p points to 0x804f494 from its allocation and still points to this address when I call malloc_dump_unreferenced().
It’s strange that malloc_g kept the information about who made the allocation but loose the information about this pointer still exists.

Read the part of the tech note with respect to heap tracing. To report
leaks, malloc_g doesn’t keep extra information about the pointer, it
goes from the root set (stacks + global data) to find everything that
the program can reach. If a block is still around, but isn’t visible to
the program, it is a leak.

This is vastly more reliable in general than wading through the output
of mtrace, for example – which falsely reports a lot of leaks.

The major thing that would impact your example is the construction of the
root set (since everything must be reachable from the root set).
The determination of the root set is complicated by several factors,
and a situation like this would depend on where pool_attr_p was defined.
Was it a global (extern) or a static variable?

it’s a global variable

Perhaps more importantly,
was it in the executable or a shared library?


Yes it’s allocated by a malloc_g in a function called main() and I call malloc_dump_unreferenced in thread created by a pool.


To construct the root set, malloc_g consults the dynamic link map
to find all the libraries linked against and looks for the extents
of the _data and _bss sections. After that it adds all the thread stacks.

If yours is in the executable that may explain something, if
the executable itself isn’t included in the link map. Please let me
know.


What do you want I verify exactly?

Where was the global declared, not where the allocation takes place.
i.e. is it in the executable (main, or something linked statically
with main), or in a shared library?


[snip]

Steve Furr email: furr@qnx.com
QNX Software Systems, Ltd.

Steve Furr a écrit :

[snip]


Yes, pool_attr_p points to 0x804f494 from its allocation and still points to this address when I call malloc_dump_unreferenced().
It’s strange that malloc_g kept the information about who made the allocation but loose the information about this pointer still exists.

Read the part of the tech note with respect to heap tracing. To report
leaks, malloc_g doesn’t keep extra information about the pointer, it
goes from the root set (stacks + global data) to find everything that
the program can reach. If a block is still around, but isn’t visible to
the program, it is a leak.

Note that as pool_attr_t has been allocated and not yet freed, it’s normal to see it in the dump, what I don’t understand is why the file and
line informations are not displayed. Do you want to say that malloc_g estimate that this address is unreachable?
If I look at the structure via this pointer with gdb just before executing malloc_dump_unreferenced(), it’s ok.
So, for any reason, It seems that the pointer is visible for my program but not visible for malloc_dump_unreferenced() point of view?

This is vastly more reliable in general than wading through the output
of mtrace, for example – which falsely reports a lot of leaks.


Where was the global declared, not where the allocation takes place.
i.e. is it in the executable (main, or something linked statically
with main), or in a shared library?

[snip]

pool_attr_p is declared in a file nammed externs.h included in all my source files including externs.c which ‘create’ the pointer.
memory pointed by pool_attr_p is allocated in fct_nto.c and all these files are linked together with recursive makefiles.
the command line is:
qcc -Vgcc_ntox86 -o/home/…/DataServer_g externs.o fct_nto.o io_funcs.o main.o posix.o -L. -L/usr/local/lib -L/usr/support/nto/x86/gcc/lib
-L/usr/support/nto/x86/lib -L/x86/lib -L/x86/usr/lib -ltcl8.3 -lmalloc_g -g


thanks,
Alain.