-3

Dear Members, I have confusion whether I am releasing the memory at correct place or not. specially *sResult?

int ReadToSerialPort( char *psResponse, int iMax)  
{  

    size_t iIn;  

    if ( fd < 1 )  
    {  
        printf( "port is not open\n" );  
        return -1;  
    }       

    iIn = read( fd, psResponse, iMax-1 );     
    if ( iIn < 0 )      
    {
        if ( errno == EAGAIN )  
        {  
            printf( "The errror in READ" );  
            return 0; // assume that command generated no response      
        }  
        else  
            printf( "read error %d %s\n", errno, strerror(errno) );  

   }  
   else   
 psResponse[(int)iIn<(int)iMax?iIn:iMax] = '\n';   

  return iIn;   

} // end ReadAdrPort  
int MultiQuery ()  
{  
    // check database connectivity   

 // code to check  DB

     while (1)  
     { //while start   

         // char *sResult = NULL;  
          char  *sResult = (char *)malloc(4096);   

          // Reading from H/W  
          if ( ( ReadToSerialPort(sResult,4096) ) > 0 )      
          {   

              // code to trim read line and put into db....   



            printf(" before free is %s\n", sResult);   

             free(sResult);        
             sResult = NULL;    
         } // end ifReadToSerialPort >0     

        //*sResult = NULL;    


     } // while(1) ends;      

    fclose(errorlog);  
    fclose(errorlog2);   
    mysql_close(&mysql);   
    return 0;  
}
3Doubloons
  • 2,088
  • 14
  • 26
samprat
  • 2,150
  • 8
  • 39
  • 73
  • 9
    Removed C tag as there is substantial quantities of C++-specific code in here. I also downvoted, because you just threw hundreds of lines of code at us without doing any work for it yourself. Do you *think* that it leaks? Did you go through and check all your allocations against your deallocations? – Puppy Jan 10 '11 at 15:31
  • 3
    I didn't down-vote the question, but your code is formatted terribly. – Alain Jan 10 '11 at 15:34
  • 1
    So you wrote all of this yourself, using portions of the C++ library, and the mySQL API and have no idea if you need to free anything? Personally, I don't think you wrote this. – Moo-Juice Jan 10 '11 at 15:34
  • 1
    Despite the blinding code you offered, Ninefingers is right. You should run your application through a profiler. If you have specific questions about the mysql api you could create a much smaller sample and point out where you are questioning it's usage. – Andrew T Finnell Jan 10 '11 at 15:36
  • HI Guys , Thanks for quick response.. I have added extended code just to give a full picture of what i am trying. The only problem or doubt , I have is to whther I am calling free(sResult) , sResult = NULL at correct position or should I call aftere readtoserialport function. I have tried few options and program runs fine in all cases . The SQL part is working fine and as I said only problem is with SResult. – samprat Jan 10 '11 at 15:38
  • HI GUys , I will trim the code to give u idea where exactly I am having doubt. – samprat Jan 10 '11 at 15:41
  • I would suggest closing this and making it a duplicate of something like http://stackoverflow.com/questions/45627/how-do-you-detect-avoid-memory-leaks-in-your-unmanaged-code or having him severely rewrite this question. While there are quite a few questions on memory allocation his wording is different so it will benefits others when they search SO. – Andrew T Finnell Jan 10 '11 at 15:42
  • When asking a question, post code in a simplified format instead of a massive wall of text. – Zac Howland Jan 10 '11 at 15:49
  • 1
    You don't need to use `malloc` here. You can just use a stack buffer since the size is hard-coded. But this is C++ - you shouldn't even be using `malloc` or C-arrays anyway. Use a `std::vector` for your buffer. – Charles Salvia Jan 10 '11 at 16:00

2 Answers2

7

Have you looked into tools for detecting memory leaks, such as Valgrind? (Windows substitutes)

Running these over your code will show you how much memory you're leaking and quite possibly where.

This isn't a complete program, so we can't pass it through for you. Some advice:

  • Break up routines and have separate test executables so you can ensure bits of your code are free of memory leaks. This is kind of like test driven development - you write a test for a function to ensure it works and validates input correctly, and you test it for memory leaks too.
  • Develop in a library like fashion. This ought to be second nature as it optimises code reuse (don't repeat yourself unless repeating yourself is advantageous) and helps with the above.

Edit: I'll expand on that. To give you an idea of when a memory leak happens, consider this:

#include <iostream>

using namespace std;

int main(int argc, char** argv)
{
    int* arr = new int(5);
    // delete arr; // <-- uncomment this to fix memalloc bug.
    return 0;
}

This program very simply allocates 4 bytes on the heap, then exits without tidying up that memory.

Valgrind would tell you:

HEAP SUMMARY:
==23008==     in use at exit: 4 bytes in 1 blocks
==23008==   total heap usage: 1 allocs, 0 frees, 4 bytes allocated
==23008== 
==23008== LEAK SUMMARY:
==23008==    definitely lost: 4 bytes in 1 blocks
==23008==    indirectly lost: 0 bytes in 0 blocks
==23008==      possibly lost: 0 bytes in 0 blocks
==23008==    still reachable: 0 bytes in 0 blocks
==23008==         suppressed: 0 bytes in 0 blocks

Why? Because you haven't deleted the memory you allocated with new. This is, roughly speaking, as complicated as it gets.

I say complicated as it gets because programs become big codebases rather quickly and memory leaks suddenly get more complicated. Who allocated the memory? Who freed it? Was memory allocated as part of a library? What happens when you start using arrays? You might cause indirect memory loss by freeing the outside level of the array but not the inner. See indirect memory loss.

This quickly becomes very complicated, especially when functions start allocating memory and you start using them elsewhere, and you start relying on programmatically determined memory sizes, such as lengths of strings based on user input. The maxlen+1 error is the common mistake and can make huge leaks in larger 2D arrays of data.

Edit 2 based on your new question:

Firstly, if you're using C++, I strongly suggest forgetting about malloc. Use new and delete because they understand polymorphism and objects, whereas malloc doesn't. Your constructors might not get called correctly. And if you need strings, use the string type. If you need arrays, vector will usually do.

Secondly, you are only freeing the memory if the read operation works correctly. Why? You've still allocated the memory, therefore you still need to free it, regardless of whether the read operation worked. You should also check that the memory was indeed allocated, otherwise you'll get a segmentation fault caused by accessing memory you're not supposed to access.

Edit three:

Ok, based on your comments, consider this code, which is what I think you're proposing:

char* buffer = (char*)malloc(4096*sizeof(char));

if ( ReadToSerialPort(buffer, ...) > 0 ) // you are proposing to free in this func call
{
    // do stuff A

}

// do stuff B

// free(buffer); // <-- you should free buffer here

What happens if you free inside the function call? Well, that's actually sort of ok, apart from the fact there's still a variable in the scope of this code that you might accidentally use. If you do, you'll be accessing memory you've explicitly released, which will probably cause your program to crash.

I assume at some stage you want to use this buffer either at part A or B. In which case you need that memory still to be allocated.

As for only freeing inside the if statement, that's a guaranteed memory leak if the read function doesn't work, because that memory never gets freed.

Here's how you should do it:

//
// I maintain you should use a string here, or 
// if you insist on char*, use new.
// and delete.
//
char* buffer = (char*)malloc(4096*sizeof(char)); 

if ( buffer == NULL )
{
    // os refused the alloc.
    cout << "Out of memory\n" << endl;
    return 1;
}

if ( ReadToSerialPort(buffer, ...) > 0 ) // this call frees as well?
{
    // do stuff A using buffer

}

// do stuff B using buffer

free(buffer); // <-- you should free buffer here

Edit 4: Just for clarification:

Do not mix malloc/free and new/delete. If you malloc, free that memory, if you new, delete that memory. If you're interfacing with the C code, unless it requires an array of something like int, you can use the string type and there's no need for dynamic allocation. Unless you're passing to a C function you have no control over, you should probably consider vector above an array. Only if you are passing to a C function you have no control over should you need to enter the world of C's malloc and free methods.

Community
  • 1
  • 1
  • Thanks Ninefingers, But I am freeing up the memory. THe only concerned is if i am freeing up at right place or not.And also instead of free(sResult) if I give *sResult = NULL just above while(1) ends, what difference it will make to my prog. – samprat Jan 10 '11 at 16:04
  • I added freeing up code inside ReadToSerialPort > 0 because I thought memory allocation is done at runtime and if ReadToSerialPort reads something then its better to free up there. And also if i add free(sResult) before while(1) ends then it will free up memory which I havnt allocated sometimes like in case when ReadToSerialPort < 0 – samprat Jan 10 '11 at 16:12
  • Not a good idea, especially as you've tried to write NULL to that memory address at a later point in the code! Edit - ah that's been commented out. But look, is it clear what happens to that memory from your call to ReadToSerialPort when reading the code? –  Jan 10 '11 at 16:13
  • I didnt get ,u sorry. What if I write like if(ReadToSerialPort(sResult, 1024) > 0 ){ // line of code}// end ofReadTOserialPOrt > 0 *sResult = NULL; } // While(1) ends – samprat Jan 10 '11 at 16:20
  • Thanks a lot Ninefingers. I will try to implement using string. My only hesitation of using new was that since lot of other codes in this file is based on C language. But since you have cleared my doubt , I have more courage to try other methods as well. – samprat Jan 10 '11 at 16:48
  • The basic rule is don't mix `new` and `malloc` memory, i.e. don't try to `free` something malloc'd and don't delete something `new`'d. However, that said, if you need a C string from a C++ string, use `stringname.c_str()`. –  Jan 10 '11 at 16:50
  • HI Ninefingers, Just to grasp better idea about malloc. since now I am freeing up buffer outside the ReadtoSerial block , do you think my code will try to free up the buffer which it hasnt allocated specially incase when ReadtoSerialport < 0.? – samprat Jan 10 '11 at 17:13
1

A quick use of Ctrl+F (because you posted way too much irrelevant code), shows that the only memory you allocate is for *sResult, and there are no exit clauses before the time that you free that memory, so yeah. After skimming this code, I hesitate to use the phrase "you're doing it right", but you are doing it.

Alain
  • 26,663
  • 20
  • 114
  • 184
  • Thanks Alain, So is it that I am freeing up memory at correct place?. But what if ReadTOSerialPort< 0 but above I am allocating SResult = (char *) malloc(4096). So IS there is any flaw if ReadToSerialPort < 0 as I am freeing memory only when it is greater than 0. – samprat Jan 10 '11 at 16:01
  • This is only true as long as the functions he calls in between `malloc` and `free` do not throw any exceptions, since he doesn't have any exception handling in this wall of code he posted. Its not an issue if none of the functions he's calling can `throw`, though. – Zac Howland Jan 10 '11 at 16:03
  • samprat, you had two calls to the free statement - one was outside the if statement. Now that you've trimmed the amount of code posted I cannot see where it is. – Alain Jan 10 '11 at 16:23
  • Hi Alain, I am freeing up memory inside the if(ReadToSerialPort> 0) but I am wondering what are pitfalls if if i comment free (SResult) and put *sResult = NULL; after closing of ReadToSerialPort – samprat Jan 10 '11 at 16:33
  • Setting the pointer to null will mean that the memory is never freed. If you call malloc(), alloc(), or realloc(), then you MUST at some point call free() on that pointer. – Alain Jan 10 '11 at 16:39