Re: Questions about memory management



On 28 May 2007 21:20:06 GMT, HS <stone.harlan@xxxxxxxxx> wrote:

**ALL CODE WRITTEN IN LINUX AND COMPILED WITH GCC**

Because of my current situation I do not often get to the Internet,
therefore this post will have to be a little long for most people's
taste, I apologize.

I am a beginner working from a book called "Linux Programming By
Example, The Fundamentals" by Arnold Robbins. In chapter three of
this book the end exercise is to write a routine that will get an any
length line from a file using dynamic memory so as not to have any
arbitrary boundaries. The only other material I have had to study is
the K&R C Standard so I am from time to time a little lost in the
sauce and my code is embarrassingly simple minded (hopefully that will
change with experience).

The first question is: In the writing of this code a I recompiled and
ran it a few hundred times identifying I think every memory leak
possible along with lots of buffer over and under runs and plenty of
other memory ailments. Does all of this memory screw up cause any
permanent damage to my computer? The books both said to avoid things

Not likely. There is a pathological case where the undefined behavior
resulting from buffer overrun could result in your program executing
code in your operating system and deleting files or causing other
havoc (can you spell virus).

like freeing the same memory twice, using freed memory etc. but

Both yield undefined behavior as nefarious as buffer overruns.

neither mentioned what the long term results are of these mistakes. I
am hoping that when the operating system takes back control from my
program it frees any unfreed memory and destroys any allocations that
were given to the program at run-time or start-up. Am I correct in

In a well designed operating system that is what should happen.

this assumption or do I now need to do something to fix a whole bunch
of crap I have littered all over the ram of my computer? Please
explain if you have time.

You need to ask in a newsgroup that discusses your operating system.
Remember, there is more than one Linux.


The second question is: Please take a look at the attached code if its
not to much trouble point out any place where I wrote silly code,
glitch code, or spaghetti code. I don't know anyone else who knows
about this stuff and I don't know where those people are to be found
(except in colleges which does not apply to me at the moment).
Therefore I get no constructive criticism.

The third question is: Can anyone recommend some further reading on
memory management to me? I think code below will show that I have
probably not fully grasped the concept yet (at least I don't feel that
I have) so if anyone can please tell me where to find some more info
(a book that I could order from amazon perhaps) on memory management I
would really appreciate that.

The fourth question is: I have notice that many routines in the
library, strdup() for example, malloc() memory but then

strdup is not a standard library function.

never free it before return, for the obvious reason that it is pretty
tough to return a pointer to freed memory. Is there some kind of
memory management at play here that I cannot see? Or is it somehow up
to the programmer to know which library calls are going to malloc() so
he or she can free them?

Any function that allocates but does not free memory should identify
this fact in its documentation. It then becomes the responsibility of
the calling function to free (or make arrangements further up the
calling tree to free) the memory. A typical example is fopen. You
have no idea what it does internally but you do know you should call
fclose to clean up when you are done with the file. If fopen does
allocate memory, fclose will free it.


The last question is: This code does throw one warning:

getline.c:76: warning: incompatible implicit declaration of built-in
function 'exit'

What is this supose to mean... it still works... but?

It means you did not include the header file which contains the
prototype for exit. Your are missing stdlib.h. As a result, the
compiler is obliged to assume that exit returns an int. However, the
compiler knows that exit returns void. void and int are incompatible
as return types.


Thank you for having taken the time to help me out here, I really
appreciate it.

//-----------------------------------------
GETLINE.C-----------------------------------------//

#include <stdio.h> // Not even sure which of these I really need

You do need this (for getc at least).

#include <malloc.h>

This is a non-standard header. Everything you need for malloc and
friends should be in stdlib.h.

#include <memory.h>

What do you think you need this for?

#include <unistd.h>

This is another non-standard header (which I don't see any need for in
your code).

#define MEMCHUNK (sizeof(char) * 50) // Get a chunck of memory size
50Xchar

Due to usenet word wrap, many of your // comments cause syntax errors
for people who copied your code and tried to compile it. For posting
messages, use /* */ comments.

Are you aware the sizeof (char) is always 1 and therefore contributes
nothing to the ultimate value of MEMCHUNK?



struct line { // This is the struct the book wanted used
size_t buflen; // The only other rules to the assignment
char *buf; // Were not to use fgets but rather getc
FILE *fp; // It has to be capable of reading memory from a
file
} *sp; // Later I will have to update this project
// To make it take care of \ continue lines
char *getline(FILE *infile); // And have it handle \n lines
char *getmore(char *buf, size_t *amount); // Have a contingency for
CR-LF
// And finally rewrite the whole thing to use fgets()

char *getline(FILE *infile)
{
struct line thisline; // Struct used to store the line being
read

thisline is an automatic variable and will exist only for the life of
this function.

char c, *pa, *end, *start; // Some pointers used for the buffer
size_t csize; // A variable to store the size of a char
unsigned long int offset; // Used later on as a place holder for
pa
int i = 0;
sp = &thisline; // Set sp to point at our struct

sp now points to an automatic variable. Any function that calls
getline and then tries to use the value in sp invokes undefined
behavior.


csize = sizeof(char); // Get the sizeof a char on this system

If the answer is not 1 you are not using C.


sp->buflen = MEMCHUNK; // Start with 10 char long buffer

Since MEMCHUNK is 50, your comment makes no sense.

sp->fp = infile; // Tell routine where to find file

sp->buf = malloc(sp->buflen); // Call malloc to get memory
if(sp->buf == NULL) // Check to see if malloc was able to get
memory
{
free(sp->buf); // If not free up the memory (just to be
sure)

Since buf is NULL, you know no memory was allocated. However, the
free function is one of the few that willingly accepts an input of
NULL so this code is only a waste and not a problem.

return NULL; // And return NULL for error
}

start = sp->buf; // Set the start, end, and pointer markers for
the buffer
end = start + sp->buflen;

end now points one byte beyond the allocated memory. This is legal
only as long as you don't dereference end.

pa = start;

while(c != '\0') // While the first line isn't terminated

c was not initialized as part of its definition and never assigned a
value in any previous statement. Therefore, its value is
indeterminate. Any attempt to evaluate an indeterminate value yields
undefined behavior.

{
c = getc(sp->fp); // Get the next char

getc returns an int. It is entirely possible for it to return a value
that will not fit in a char. If it does so, you won't be happy with
the result.

You never opened fp. Did you expect the calling function to do so?

if((end - pa) < (csize * 2)) // If there isn't enough room
left
{
offset = (pa - start); // Save the offset of pa
sp->buflen = (sp->buflen + MEMCHUNK); // Grow buflen

sp->buf = getmore(sp->buf, &sp->buflen); // Attempt to grow memory

Why are you passing the address of buflen to getmore instead of its
value? getmore doesn't change the value so this is an unnecessary
complication.


start = sp->buf; // If it grows re-establish pointers
pa = start + offset;
end = start + sp->buflen;
}
if(c == '\n' || c == EOF) // Whenever we hit the newline or
EOF marker

Don't you think this check should come before you start expanding your
buffer?

{
c = '\0'; // Set c to \0 this will terminate the string
}
*pa = c; // By now we have filtered c and can assign it in
the buffer
pa++; // Jump to the next char position in the buffer
}
return sp->buf; // Send the location of the string in memory
// back to the calling routine

The return is legal (because it passes back the value) but sp no
longer points anywhere.

}

char *getmore(char *buf, size_t *amount) // This is a wrapper to save
us if realloc fails
{
buf = realloc(buf,*amount); // Realloc memory requested

If realloc fails, the old allocated memory, pointed to by buf, is
still allocated. However, realloc returns NULL which you immediately
store in buf. The end result is you have lost your pointer to the
allocated memory and have a memory leak. The recommended approach is
tmp_ptr = realloc(real_ptr, amount_desired);
if (tmp_ptr == NULL) {appropriate error handling}
else real_ptr = tmp_ptr;
return real_ptr;

if (buf == NULL) // Make sure it worked
{
free(buf); // If not be nice and free whatever may be there

Another waste.

printf("Error: getmore failed\n"); // Print an error
exit(2); // And get the hell out

2 is not a portable exit value. Use EXIT_FAILURE which is defined in
both stdio.h and stdlib.h.

}

return buf; // If everything is good return your buffer start
point
}

// As written the code when compiled and called from another routine
will kick back the first line of any file

Most compilers would generate a diagnostic about using c before it is
initialized. Maybe you need to up your warning level.

// No matter the length so long as the line is not so long as to cause
a SEGFAULT (that would have to be a
// pretty damn long line) however I still am not sure that the memory
management is completely airtight here.

// Some pieces of this code (such as saving the buffer offset pa when
allocating more memory)
// did come from the book "Linux Programming By Example, The
Fundamentals" By Arnold Robbins. Dont know if anyone
// cares but hey, credit where it's due right?
//-----------------------------------END
GETLINE.C---------------------------------//


Remove del for email
--
comp.lang.c.moderated - moderation address: clcm@xxxxxxxxxxxx -- you must
have an appropriate newsgroups line in your header for your mail to be seen,
or the newsgroup name in square brackets in the subject line. Sorry.
.



Relevant Pages

  • Re: Problem with linked list
    ... !pool and see what piece of memory has ... allocated (thankfully you tag your allocations). ... > The buffer is filled the following way: ... >> what's in the section of MYSTRUCT (which you don't appear to have ...
    (microsoft.public.development.device.drivers)
  • RE: 2003 SBS stalling randomly
    ... A memory leak occurs in an application using the Volume Shadow Copy Service ... Poolmon displays data that the ... The data is grouped by pool allocation tag. ... Press P twice to display allocations from only the paged pool. ...
    (microsoft.public.windows.server.sbs)
  • Re: xmalloc string functions
    ... than a NULL return from malloc(). ... pointer value to null at the point I want to trigger the failure. ... I've also had VMWare report out-of-resource at times when the only resource that was tight was memory, and again it gave me the chance to recover the situation which saved me significant work because I had two VMs running and the state between them was important and took time setting up. ... allocations without reference to other circumstances (number of ...
    (comp.lang.c)
  • Re: System pretends to be out of memory when it isnt
    ... With 1Gb of memory I can usually copy dozens of photos ... >>> to analyze Windows heap allocations for a specific process. ... >>> discusses how you can use UMDH to help locate memory leak problems. ... the maximum stack trace depth is 16. ...
    (microsoft.public.windowsxp.general)
  • Re: xmalloc string functions
    ... than a NULL return from malloc(). ... pointer value to null at the point I want to trigger the failure. ... There are about five bazillion allocations, ... Memory is quite a different kind of resource. ...
    (comp.lang.c)