Jump to content
  • Advertisement
Sign in to follow this  
Floating

How can a buffer overrun happen?

This topic is 5128 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I am wondering how a buffer overrun can happen. My application shows an error message saying: "Buffer overrun detected! A buffer overrun has been detected which has corrupted the program's internal state. The program cannot safely continue execution and must now be terminated" When debugging I cannot find where the error actually happens because the message is displayed when I close the application (or in some other special cases). I have a main class that is initialized at program start: the class's member variables are initialized in the constructor and during initialization of a simple float, the class's address suddenly becomes NULL and all other member show "Expression cannot be evaluated" (when debugging). But at that time no error message is displayed and the execution can continue until I close the program. I tried to isolate the error and now basically have just a class that initializes variables before being deleted. However the error message is still displayed! Help please, I am a little bit lost EDIT: The debugger also behaves strangely sometimes: it would not always follow the execution sequence as displayed but jump over some commands without executing them!

Share this post


Link to post
Share on other sites
Advertisement
Well, are you writing past the "boundary" of an array?

The following is problematic, for instance:
int array[10]; // change to int *array = new int[10]; to allocate on the heap.
for ( unsigned i = 0; i <= 10; ++i )
array = i;



because it writes to array[10] which is not part of the array as you declared it. Whatever you write to beyond index 9 is going to go either into unused memory, or sometimes overwrite another variable. This example will actually crash the program because the array is allocated on the stack and not on the heap. Buffer overruns also happen when copying a section of memory of which you do not know the size to a section of memory that is too small to accomodate it (for instance for c-style strings).

You might want to take a look at this, and this courtesy of Google.


To be more specific, though, it would be easier if we saw some of your code.

Regards,
jflanglois

[Edited by - jflanglois on November 28, 2004 1:25:37 AM]

Share this post


Link to post
Share on other sites
This is a buffer.


char helloworld[10];
// [ 0 ] [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ] [ 9 ]


Now we try to put stuff in there, and get a buffer overrun:


strcpy(helloworld, "Hello World\n");
// [ H ] [ e ] [ l ] [ l ] [ o ] [ ] [ W ] [ o ] [ r ] [ l ] d \n \0


See how the extra characters don't fit in the buffer? That's bad. That means they're in some space that you didn't explicitly provide for them. Depending on the context, and your platform, that could mean:

- They are overwriting the bytes of another variable
- They are overwriting some header or v-table for an object, thus corrupting it
- They are overwriting other book-keeping information created by the compiler to keep track of memory allocations, meaning all hell breaks loose
- They are overwriting the return value of the current function, meaning that when the current function finishes, the processor will gleefully jump off to some random location and execute the code there (Note: a clever person who knows there is such a problem in your program can frequently arrange for this location to be not-so-random. That's Bad News, especially if your program is running as root on a Unix-like system.)
- They are trying to write to memory that doesn't even belong to your process, causing a segmentation fault (on Unix-like systems), a "Windows has encountered a problem" dialog or similar (on recent Windows), or possibly worse things (on older MacOS and older Windows - in these cases it will often freeze the computer up solid.)

These are all very very very bad things, which are why you should never use char *'s to represent text strings in C++, and never ever ever use the unsafe C library functions. (Edit: Actually, there are more reasons for using std::string for text strings instead of char * stuff, but it doesn't seem appropriate to go into them here.) You should consider these to be reserved for the use of systems programmers with years of field experience, who are qualified to prove for 100% sure that they know exactly what they are doing, and are prepared to accept the consequences of being wrong.

Share this post


Link to post
Share on other sites
Quote:
These are all very very very bad things, which are why you should never use char *'s to represent text strings in C++, and never ever ever use the unsafe C library functions. (Edit: Actually, there are more reasons for using std::string for text strings instead of char * stuff, but it doesn't seem appropriate to go into them here.) You should consider these to be reserved for the use of systems programmers with years of field experience, who are qualified to prove for 100% sure that they know exactly what they are doing, and are prepared to accept the consequences of being wrong.


I'm never 100% sure that the code I'm writing is going to work flawlessly, but when it doesn't, the worst case is "MyProgram.exe has performed an error and needs to close.", and the often case is that an error occurs in some random section of my code, that worked earier.

'memset' & 'memcpy' are my two favorite functions now: how dare you call them very very bad [bawling]. I can't believe I went months without them: they can do soo much, in soo little code. Not to mention, the performance of my programs are astronimical (I came from Visual Basic 5/6).

Than again, I work in strict-C, so your prolly right that these shouldn't get used in C++: I've never used C++, never have, never will. And if you want to learn about Buffer overflows, just try learning memcpy from experiance (It's how I learned [smile]): seriously, a buffer overflow isn't the end of the world in development, when code that worked yesterday, isn't working today, than isn't it obvoius what has happened?

I've completely discontinued use of strcpy though: I HATE that it attaches a null pointer on the end of the string automatically, and without option (BUFFER OVERFLOW danger). Its really not that difficult to just add a null terminator manually to the array, and than use memcpy to copy it over.

Share this post


Link to post
Share on other sites
Thank you very much for the nice explanations.
What I don't understand is why is my buffer overrun not detected when it actually happens? The error message is displayed when quiting the application (after leaving the main-function).
Also in that case how can I trace back to the point where the error happened? My debugger shows me just a call stack of 3 and all are is nome kind of dll (not mine) that can't be debugged.

Share this post


Link to post
Share on other sites
Quote:
Original post by Floating
Thank you very much for the nice explanations.
What I don't understand is why is my buffer overrun not detected when it actually happens? The error message is displayed when quiting the application (after leaving the main-function).

Visual Studio adds some code that checks the status of your arrays when they go out of scope/get deleted. It doesn't perform the check every time you write, so there's no way to figure out when, exactly, the error occurs. You have to just see which array has the offending error, and work backwards from there.
Quote:
Original post by Floating
Also in that case how can I trace back to the point where the error happened? My debugger shows me just a call stack of 3 and all are is nome kind of dll (not mine) that can't be debugged.

It does show when the error happened, but its the error that caused the break. A breakpoint is called from within some debug code, signalling a corrupted heap. Because this all occurs outside of your main routine, none of the functions on your stack are going to be even remotely useful in any way.

While moving on to std::string is a good suggestion, if its not an option consider at least using strncpy. It takes an additional parameter that tells how large your output array is, thus preventing overflows if you keep track of that length properly. I'm pretty sure its part of the standard C library.

As for your other problem, regarding the class who's this pointer gets randomly set to null, I can't help. I have, however, encountered that problem, and as I recall the solution was something stupid on my part. Not much help, I know, but at least it lets you know its probably not some random compiler bug.

Also, look into this. Its gotten me out of some jams in the past.

Westeria:
strcpy not appending a null terminator makes no sense. A c-string is not a string without a null terminator, and strcpy creates a string.

CM

Share this post


Link to post
Share on other sites
Quote:
Original post by Floating
Thank you very much for the nice explanations.
What I don't understand is why is my buffer overrun not detected when it actually happens? The error message is displayed when quiting the application (after leaving the main-function).
Also in that case how can I trace back to the point where the error happened? My debugger shows me just a call stack of 3 and all are is nome kind of dll (not mine) that can't be debugged.


A buffer overflow isn't always a bad thing. For example if two string arrays are side by side, than overflowing the one, goes into the other.

That's half the amount of code you gotta write, and descent performance increase (If that function is executed (1600*1200) times per loop [razz] ). Just don't forget to use #pragma pack(1), since most compilers stuff extra bytes into your structures.

The reason your error is given upon closure, is because Window's checks the array after your program closes...

egg..

char chrString[10];

Creates...
[0][1][2][3][4][5][6][7][8][9][S][ ][ ][ ][ ][ ][ ]
Where [S] is a safe-bounds check thats automatically placed.

On closure, Window's says... is [S] still there? If yes, than close normally, if no, than give error.

If a buffer overflow occurs in the result is something like this..

[0][1][2][3][4][5][6][7][8][9][1][2][3][4][ ][ ][ ][ ][ ]

Than Window's errors you!

(This is what I remember of being told by a fellow member of GameDev.net [razz]).

Share this post


Link to post
Share on other sites
Quote:
A buffer overflow isn't always a bad thing. For example if two string arrays are side by side, than overflowing the one, goes into the other.

It isn't always a bad thing if you're trying to lose your job. Overflowing one array into the next will probably give any sort of runtime diagnostics program like BoundsChecker a fit.

memset'ing a struct is one thing that's fairly safe even if its close to undefined behavior. Purposely writing over one local array to affect another is just lazy and poor code style.

Share this post


Link to post
Share on other sites
Original post by antareus
Quote:
Purposely writing over one local array to affect another is just lazy and poor code style.


"Poor coding style" -> definently.
"Lazy" -> absolutly not.

It can be very tricky to do this without overflowing some crucial memory.

And yes, lol, you will lose your job for coding like this: unless of course your working for some ultra-high performance computing company (like Google) and using this method (Or a slight deviation) you increase database search performance by 5%!




Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!