Jump to content


Check out our Community Blogs

Register and join over 40,000 other developers!


Recent Status Updates

View All Updates

Photo
- - - - -

Understanding memory leaks and crashes in C++

c++ memory leak memory crash null pointer return local variable strlen dangling poniter

  • Please log in to reply
9 replies to this topic

#1 abha

abha

    CC Lurker

  • New Member
  • Pip
  • 6 posts
  • Programming Language:C
  • Learning:C

Posted 20 September 2012 - 01:53 PM

One innocent memory leak or a little stack corruption might keep you busy debugging for week. Crashes and memory leaks happen with everyone whether you are a naive or an expert C++ programmer.

Memory leak is failure to release memory that was acquired from the heap. It could be as simple as doing a new and forgetting a corresponding delete. On the other hand you could say it’s as complicated as dealing with a corrupt stack because while allocating an array, you forgot to reserve space for null byte termination. This article discusses reasons behind some common memory leaks and crash.

Dangling pointers:

Dangling pointer is a pointer to an already deallocated heap memory.

First scenario that causes dangling pointer is when an application tries to use object even after it has been released. This causes invalid memory access. For instance:

MyClass *obj1 = new MyClass();
MyClass *obj2 = obj1;
After the assignment of obj1 to obj2, both the object point to same heap location.

dangling_1.png

delete obj2;

dangling_2.png


Above statement destroys the memory allocated on the heap. So both object pointers obj1 and obj2 exist and are in-scope but they point to undefined storage location. Using obj1 or obj2 will cause undefined behaviour.

Dangling pointers: Return pointer to local variable:

Second scenario that causes dangling pointers is returning pointers to local variables from functions. This is because local variables go out of scope once the functions ends and the pointer becomes invalid. Consider:

MyClass* test()
{
MyClass temp;
return &temp;
}

The function test returns pointer to a local variable ‘temp’ . Once the function goes out of scope, the automatic variable ‘temp’ is destroyed.

MyClass obj = test();
obj.display();

Any attempts to access the return value from test() will have unpredictable results. Variable temp is now out of scope and the memory allocated for temp has already been destroyed.

Another amazing C++ combination, that is a store house of memory leaks, is the deadly char data type and pointers combination.

char* function( char* c)
{
char* temp = new char [ strlen (c) + 1 ];
strcpy ( temp, c );
delete[] c;  //evil, should not delete callers string
return temp;
}


int main()
{
char testStr[10] = "CODECALL";
char* retVal = function(testStr);
.....
....
delete retVal; //it is the responsibility of the caller to clear the heap
return 0;
}

Deleting the callers string ‘c’ is evil. Also, code allocates memory on the heap and returns a pointer to it. Now its the callers responsibility to deallocate the memory from the heap else a memory leak will follow.

Deallocating already freed memory:

Trying to delete memory that has already been deallocated again causes undefined behavior.

Accessing an already destroyed memory causes undefined behavior. If the storage has been realloted to another variable, this might imply that some portion of newly allocated memory is being read or being tampered causing the program to crash. In some cases, if the deallocated memory has not been reassigned, attempts to access it might return correct results. In general the program behavior is undefined.

void fun()
{
MyClass * obj = new MyClass();
obj.display()
….
delete obj;
…
…
delete obj;
}

obj has already been deleted. Attempt to delete it again causes undefined behavior.

Null pointer:

Its considered a good programming practice to assign NULL to variables once the memory they point to has been freed:

delete obj;
obj = NULL;

This avoids many programming errors as deleting a NULL pointer has no effect.

But be sure not to access methods using the NULL pointer else it might cause unpredictable behavior.

…
delete obj;
obj = NULL;
….
…
obj->display(); //if obj is null, program might crash

Buffer overflow:

C++ has no bound checks. So if memory is allotted to a variable for 8bytes but a programmer tries to write in 12bytes to that variable, C++ would permit it. This is known as buffer overflow since the remaining 4 bytes spill over and corrupt the process stack. This might crash the program. Consider the following example:

void bufferTest( char* originalStr)
{
char buf1[10];
char buf2[10];

strcpy(buf2, originalStr);
}

int main()
{
char *testStr = “CODECALL FORUM”;
bufferTest(testStr);
return 0;
}

For the function bufferTest(), a high level view of the stack frame would be like:

buffer_overflow.png


The function bufferTest’s argument points to a string of 15bytes. strcpy() does no bound checking and copies this 15bytes to a 10 byte buffer. The remaining 5 bytes spill over and overwrite the stack frame pointer (sfp). This damages the process stack. When the processing of bufferTest() is over and it tries to return, it would get some random address which is either invalid memory location or incorrect memory location. Either ways, the program crashes.

The +1 problem with chars…

Every C++ programmer has atleast once faced the ‘Null Byte Termination Trouble’. The rule of thumb is:

strlen() returns the length up to but not including the null character.

char* testStr = “codecall”;
strlen(str) would return 8 though the string is null terminated.

So when creating strings, null char at the end of the string should be taken care of.

For some string str:
char * ptr = new char[strlen(str)+1];
strcpy(p,str);


Thanks for staying by and reading…

Attached File  memory_leak_samples.zip   1.53KB   321 downloads
  • 4

#2 VNFox

VNFox

    CC Devotee

  • Senior Member
  • PipPipPipPipPipPip
  • 648 posts
  • Programming Language:C#, PHP
  • Learning:Assembly

Posted 20 September 2012 - 03:10 PM

Good article +1.
  • 1

www.pickmike.com
I don't just develop software. I find solutions to your business needs.


#3 kernelcoder

kernelcoder

    CC Devotee

  • Expert Member
  • PipPipPipPipPipPip
  • 990 posts
  • Location:Dhaka
  • Programming Language:C, Java, C++, C#, Visual Basic .NET
  • Learning:Objective-C, PHP, Python, Delphi/Object Pascal

Posted 24 September 2012 - 05:22 PM

Great tutorial! Good job abha!

However, I'm not able to understand one point in the following part in your tutorial --

...........
...........
Another amazing C++ combination, that is a store house of memory leaks, is the deadly char data type and pointers combination.

char* function( char* c)
{
char* temp = new char [ strlen (c) + 1 ];
strcpy ( temp, c );
delete[] c;
return temp;
}

Apart from deleting the callers string ‘c’ the code tries to return local variable temp, which goes out of scope once the function ends causing dangling pointer creation in the caller. The outcome of the code is unpredictable.

...........
...........

Yes, deleting the caller's string 'c' is real bad but what is the problem with returning variable 'temp' as it is created in heap?
  • 0

#4 Colanth

Colanth

    CC Addict

  • Advanced Member
  • PipPipPipPipPip
  • 165 posts
  • Location:Fayetteville, NC, USA
  • Programming Language:PHP, (Visual) Basic, JavaScript, Visual Basic .NET, Pascal, Logo, Assembly, VBScript, Others

Posted 24 September 2012 - 06:45 PM

It stops existing as soon as the 'return' is executed, since its scope is local to that function. So 'return' is returning a 'variable' that doesn't exist.
  • 0

#5 kernelcoder

kernelcoder

    CC Devotee

  • Expert Member
  • PipPipPipPipPipPip
  • 990 posts
  • Location:Dhaka
  • Programming Language:C, Java, C++, C#, Visual Basic .NET
  • Learning:Objective-C, PHP, Python, Delphi/Object Pascal

Posted 24 September 2012 - 08:03 PM

It stops existing as soon as the 'return' is executed, since its scope is local to that function. So 'return' is returning a 'variable' that doesn't exist.

Well, the variable 'temp' will not exist after the return statement in method 'function' but the memory that is created in that function which is referenced in the 'temp' variable will exist because the memory is created on the heap. Note that Heap memory does not get deleted/freed until you call 'delete' or 'free' on it.

So, what I'm saying is that the following code is bad as the memory for local variable 'temp' is created on stack --
char* danger( char* c)
{
char temp[100]; // This is real bad as the memory is created on the STACK
strcpy ( temp, c );
return temp;
}

void test()
{
char data[10] = "fewchars";
char* refPtr = danger(data);
cout << refPtr;
}



But in this following code, the memory is created on HEAP. So the memory will not free until you free the memory blocks with delete operator.
char* noDanger( char* c)
{
char* temp = new char [ strlen (c) + 1 ]; // Look, memory is creating on HEAP
strcpy ( temp, c );
return temp;
}

void test()
{
char data[10] = "fewchars";
char* refPtr = noDanger(data);
cout << refPtr; // This is OK
}

  • 1

#6 abha

abha

    CC Lurker

  • New Member
  • Pip
  • 6 posts
  • Programming Language:C
  • Learning:C

Posted 25 September 2012 - 12:10 PM

Thanks kernelcoder for bringing it to my notice. I'll soon edit the post and correct it.

As you already explained in the example, its absolutely okay to return pointer to memory allocated from the heap. But its the responsibility of the caller to take care of memory deallocation otherwise a memory leak would follow. Though its evil to delete the callers string 'c'.



char* function( char* c)
{
char* temp = new char [ strlen (c) + 1 ];
strcpy ( temp, c );
delete[] c; //evil, should not delete callers string
return temp;
}

int main()
{
char testStr[10] = "CODECALL";
char* retVal = function(testStr);
.....
....
delete retVal; //it is the responsibility of the caller to clear the heap
return 0;
}

Thanks again!!
  • 0

#7 kernelcoder

kernelcoder

    CC Devotee

  • Expert Member
  • PipPipPipPipPipPip
  • 990 posts
  • Location:Dhaka
  • Programming Language:C, Java, C++, C#, Visual Basic .NET
  • Learning:Objective-C, PHP, Python, Delphi/Object Pascal

Posted 25 September 2012 - 05:43 PM

Thanks kernelcoder for bringing it to my notice. I'll soon edit the post and correct it.

As you already explained in the example, its absolutely okay to return pointer to memory allocated from the heap. But its the responsibility of the caller to take care of memory deallocation otherwise a memory leak would follow. Though its evil to delete the callers string 'c'.

char* function( char* c)
{
char* temp = new char [ strlen (c) + 1 ];
strcpy ( temp, c );
delete[] c; //evil, should not delete callers string
return temp;
}

int main()
{
char testStr[10] = "CODECALL";
char* retVal = function(testStr);
.....
....
delete retVal; //it is the responsibility of the caller to clear the heap
return 0;
}

Thanks again!!

No problem!!!

Again, your post is good. Keep it up!
  • 0

#8 abha

abha

    CC Lurker

  • New Member
  • Pip
  • 6 posts
  • Programming Language:C
  • Learning:C

Posted 26 September 2012 - 11:09 AM

The article has been corrected..
  • 0

#9 Billi1981

Billi1981

    CC Lurker

  • Just Joined
  • Pip
  • 1 posts

Posted 27 August 2014 - 11:11 AM

Good tutorial, but one thing I would add is that in case of leaks it's useful to use special tools like http://valgrind.org on Linux or http://deleaker.com on Windows.

 

Please add to the article, it's must have!


  • 0

#10 0xDEADBEEF

0xDEADBEEF

    CC Devotee

  • Senior Member
  • PipPipPipPipPipPip
  • 790 posts
  • Programming Language:C, Java, C++, C#, (Visual) Basic, Perl, Transact-SQL, Bash, Prolog, Others
  • Learning:Others

Posted 27 August 2014 - 12:48 PM

. Though its evil to delete the callers string 'c'.
 

 

Not only evil, down right dangerous.

 

Some reasons:

  • The pointer might not point to the heap
  • The pointer might not be allocated with the allocator you think it has
  • The pointer might be not point to the whole allocated block of memory

  • 0

Creating SEGFAULTs since 1995.






Also tagged with one or more of these keywords: c++, memory leak, memory crash, null pointer, return local variable, strlen, dangling poniter