Heap Corruption Detected – Why and how to avoid a buffer overrun

For our first coding adventure I’d like to share with you a problem I’ve ran into today. I was working away on a class to load GLSL shaders from disk, for one of my OpenGL projects. It happened that I had to copy the content of a file from a std::stringstream into a char array. So I said “OK it’s no big deal, let’s do that!”. I wrote a small snippet to copy just a string into a char array, let’s consider the following program:


int main(int argc, char* argv[])
{
     std::string aString = "I'm a string";

     char* output = new char[aString.length()];

     aString.copy(output,aString.length(),0);

     printf("%s",output);

     return 0;
}

The output though has a small surprise:

 

 

Hmm…I clearly forgot to add the null character to terminate the string. Let’s then do it:

int main(int argc, char* argv[])
{
    std::string aString = "I'm a string";

    char* output = new char[aString.length()];

    aString.copy(output,aString.length(),0);

    output[aString.length()] ='\0';

    printf("%s",output);

    return 0;
}

The output this time looks alright:

So far so good. No problem whatsoever neither from the compiler nor from the linker nor during runtime. Some of you might have already noticed I made two mistakes though. First off I clearly forgot to delete the output variable to release its memory after its use. In this very example it would not matter really but in a more complex program it would cause a memory leak. Let’s then add the delete statement:

int main(int argc, char* argv[])
{
    std::string aString = "I'm a string";

    char* output = new char[aString.length()];

    aString.copy(output, aString.length(), 0);

    output[aString.length()] ='\0';

    printf("%s",output);

    delete[] output;

    return 0;
}

Try hit F5. You would incur more likely (only if you are using the Visual C++ compiler) into this debug error:

 

Visual C++ is not happy…

First time I dealt with this problem it took me a while to figure out what was causing it and that exception totally caught me off guard. I looked up the error and I found out that heap corruptions are caused by writing too much to a memory buffer. In our case, and this was my second mistake, I put the null character off the memory allocated for the output char. This is a rookie mistake you would think and in fact it is but heap corruptions only manifest the next time you try to do something with the heap itself, like allocate more memory or free/delete a block of memory, so it wouldn’t occur after the end of the buffer is overwritten. Solution is very simple: add one byte to the allocation of output:

char* output = new char[aString.length() + 1];

Here it was very easy to spot and to nail it down, but in bigger code-bases it can take hours to understand where exactly you have overwritten after the end of a buffer.

Another solution would be to use safer functions that returns Checked iterators like sprintf_s for example. Be always very careful when you copy strings into manually allocated memory block. It can take up a lot of time to spot a bug that could be caused in a part of your code you would not suspect.

4 thoughts on “Heap Corruption Detected – Why and how to avoid a buffer overrun

  1. Hi Giovanni,
    Nice article – thanks for sharing.
    I think the correct way to delete the output buffer here would be as follows (using []):

    delete[] output;

    Regards,
    Tim.

    Like

  2. a better way is not to manually maintain the buffer, rather use vector
    and then use std::copy, std vector will autoresize to fit the string!

    This is a common scenario and I can dig the exact code I use in production if you want me to!?

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s