Getting Segmentation Fault, selectively, on memory overwrite.

V

Vishal Grover

Hello Everyone,

I am seeing a certain behaviour which I find strange, and am curious to get an
explanation to it. I have the following program.

#include <iostream>
#include <cstdlib>

using namespace std;

int main(int argc, char ** argv) {
if(argc<2) {
return -1;
}

int value = atoi(argv[1]);
char * arr = new char[value];
// No segmentation fault unless next is an array.
char * next = new char[value];

int i = 0;
for(i=0; i<value; i++) {
arr = 'a';
next = 'a';
}
// NOTE: I am adding a char beyond the array boundary
arr='\0';
next='\0';
// This causes a segmentation fault
delete [] arr;
}

I compiled this with 3.2.2 on Red Hat Linux 9 on an Intel i686. When I run the
program, it gives me a Segmentation fault only when the array size is an odd
multiple of 4. My guess is it has something to do with word alignment. But, what
exactly is happening here?

Thanks for your help,
Vishal Grover
Developer
Trilogy Software Inc.
 
K

Kevin Goodsell

Vishal said:
Hello Everyone,

I am seeing a certain behaviour which I find strange, and am curious to get an
explanation to it. I have the following program.

#include <iostream>
#include <cstdlib>

using namespace std;

int main(int argc, char ** argv) {
if(argc<2) {
return -1;
}

int value = atoi(argv[1]);
char * arr = new char[value];
// No segmentation fault unless next is an array.
char * next = new char[value];

int i = 0;
for(i=0; i<value; i++) {
arr = 'a';
next = 'a';
}
// NOTE: I am adding a char beyond the array boundary


If you know this, why are you surprised that the program doesn't behave
well?
arr='\0';
next='\0';
// This causes a segmentation fault
delete [] arr;
}

I compiled this with 3.2.2 on Red Hat Linux 9 on an Intel i686. When I run the
program, it gives me a Segmentation fault only when the array size is an odd
multiple of 4.


That's perfectly acceptable behavior for a program with undefined behavior.
My guess is it has something to do with word alignment. But, what
exactly is happening here?

Undefined behavior.
Thanks for your help,
Vishal Grover
Developer
Trilogy Software Inc.

I'm considering making a note of this company's name so I can be sure
never to buy software from them... Can you explain *why* you are
intentionally overflowing an array in your code, in order to restore
some of my confidence in the software industry?

-Kevin
 
J

Josephine Schafer

Vishal Grover said:
Hello Everyone,

I am seeing a certain behaviour which I find strange, and am curious to get an
explanation to it. I have the following program.

#include <iostream>
#include <cstdlib>

using namespace std;

int main(int argc, char ** argv) {
if(argc<2) {
return -1;
}

int value = atoi(argv[1]);
char * arr = new char[value];
// No segmentation fault unless next is an array.
char * next = new char[value];

int i = 0;
for(i=0; i<value; i++) {
arr = 'a';
next = 'a';
}
// NOTE: I am adding a char beyond the array boundary


But why? You haven't allocated enough space to write another extra
character.
Strings do end with a null character but then you need to allocate space for
that null character
also. I hope you know that.

Taking that into consideration -
char * arr = new char[value + 1];
char * next = new char[value + 1];
should be what would get you the desired result.

HTH,
J.Schafer
 
V

Vishal Grover

Kevin Goodsell
If you know this, why are you surprised that the program doesn't behave
well?

Because, this is a test case which I had written to investigate a bug. I am
not questioning the fact that the program doesn't behave well. My question
is why isn't the behaviour not uniform for each input value.
That's perfectly acceptable behavior for a program with undefined behavior.

Nowhere have I claimed that the behaviour is not acceptable. I am just looking
for an explanation for the behaviour.
Undefined behavior.

No machine or compiler, at least the non-quantum ones, has a non-deterministic
behaviour, given perfect knowledge about the system. In case you did not
get the question, I was looking for an insight on how does a popular
compiler like gcc handle undefined behaviour.
I'm considering making a note of this company's name so I can be sure
never to buy software from them... Can you explain *why* you are
intentionally overflowing an array in your code, in order to restore
some of my confidence in the software industry?

Since when is it a bad practice, to write a test case to investigate a potential
bug? You have no right to question the quality of software that
my company makes, based on what I has been given in this mail. If you can't
supply a decent answer, or even if this is not the right place to ask the
question, you have absolutely no right to be rude and make such judgemental
statements.

Thank you very much Kevin, I will not be posting any further questions on this
list

Vishal
 
V

Vishal Grover

Josephine,

I am sorry, if I did not ask the question clearly enough.
But why? You haven't allocated enough space to write another extra
character.
Strings do end with a null character but then you need to allocate space for
that null character
also. I hope you know that.

Yes, I know that and I am overwriting the memory intentionally. I was curious
to know, how would a typical compiler handle such a case. Yes, the behaviour
is indeed undefined according to the language standards in such a case. However,
given a combination of Operating System and Compiler, the behaviour of the
program will have an explanation and I was interested in that explanation.
Maybe, this group is the wrong place to ask this question.
Taking that into consideration -
char * arr = new char[value + 1];
char * next = new char[value + 1];
should be what would get you the desired result.
HTH,
J.Schafer

Thank You,
Vishal
 
K

Kevin Goodsell

Vishal said:
Kevin Goodsell




Because, this is a test case which I had written to investigate a bug. I am
not questioning the fact that the program doesn't behave well. My question
is why isn't the behaviour not uniform for each input value.

There is no C++ language answer for that. You might be able to get an
answer from the compiler vendor. All the C++ standard has to say about
it is that it places no requirements on the program's behavior.
Since when is it a bad practice, to write a test case to investigate a potential
bug? You have no right to question the quality of software that
my company makes, based on what I has been given in this mail. If you can't
supply a decent answer, or even if this is not the right place to ask the
question, you have absolutely no right to be rude and make such judgemental
statements.

You posted blatantly broken code without an explanation or any
indication that you understood that it was broken. What conclusion
should I draw from that? I only asked for an explanation, to hopefully
show my conclusion was wrong.
Thank you very much Kevin, I will not be posting any further questions on this
list

It's a group, not a list. Honestly, I care very little whether you
participate or not. But this is a rather trivial thing to resort to
self-banishment over.

-Kevin
 
A

Alf P. Steinbach

I am seeing a certain behaviour which I find strange, and am curious to get an
explanation to it. I have the following program.

#include <iostream>
#include <cstdlib>

using namespace std;

int main(int argc, char ** argv) {
if(argc<2) {
return -1;
}

int value = atoi(argv[1]);
char * arr = new char[value];
// No segmentation fault unless next is an array.
char * next = new char[value];

int i = 0;
for(i=0; i<value; i++) {
arr = 'a';
next = 'a';
}
// NOTE: I am adding a char beyond the array boundary
arr='\0';
next='\0';
// This causes a segmentation fault
delete [] arr;
}

I compiled this with 3.2.2 on Red Hat Linux 9 on an Intel i686. When I run the
program, it gives me a Segmentation fault only when the array size is an odd
multiple of 4. My guess is it has something to do with word alignment. But, what
exactly is happening here?


As others have answered, the only general answer is that you're invoking
undefined behavior, where anything or nothing may happen.

In practice it seems your compiled program is overwriting some allocation
information.

Such information is typically placed right before a dynamically allocated
item. That seems to fit the alignment issue you have noted. It's no
great mystery, but it has nothing to do with C++.

On the topic of C++, in order of appearance in the above code:


* Guideline: don't use atoi, since it has no error checking.
Exception: where you want 0 as result in case of error (add comment).

* Guideline: don't use raw pointers and arrays, use smart pointers and
standard library containers.

* Guideline: avoid using a loop control variable after the loop.

* Guideline: always execute a corresponding 'delete' for each 'new'.

* Guideline: when you rely on the return value 'main' to indicate
failure, express success explicitly by returning EXIT_SUCCESS.


Finally, Word of Advice: don't take technical comments personally and
threaten to "leave this list", as you seem to have done; see e.g.
<url:http://www.winternet.com/~mikelr/flame52.html>.
 
N

Noah Roberts

Vishal said:
Josephine,

I am sorry, if I did not ask the question clearly enough.




Yes, I know that and I am overwriting the memory intentionally. I was curious
to know, how would a typical compiler handle such a case. Yes, the behaviour
is indeed undefined according to the language standards in such a case. However,
given a combination of Operating System and Compiler, the behaviour of the
program will have an explanation and I was interested in that explanation.
Maybe, this group is the wrong place to ask this question.

You cannot know for sure what will happen when you write past a
dynamically created storage area. You could be attempting to overwrite
basically anything. Maybe the next byte is yours, maybe it isn't.
There is not even a compiler specific answer.

You can know what you will be overwriting if you go past a stack
allocated memory segment. Usually this will be more stack variables and
eventually the return value. This is how buffer overrun exploits occur.

NR
 
J

Josephine Schafer

Vishal Grover said:
Josephine,

I am sorry, if I did not ask the question clearly enough.
But why? You haven't allocated enough space to write another extra
character.
Strings do end with a null character but then you need to allocate space for
that null character
also. I hope you know that.

Yes, I know that and I am overwriting the memory intentionally. I was curious
to know, how would a typical compiler handle such a case. Yes, the behaviour
is indeed undefined according to the language standards in such a case. However,
given a combination of Operating System and Compiler, the behaviour of the
program will have an explanation and I was interested in that explanation.
Maybe, this group is the wrong place to ask this question.
Taking that into consideration -
char * arr = new char[value + 1];
char * next = new char[value + 1];
should be what would get you the desired result.
HTH,
J.Schafer
OK may be I can attempt to give you some insight on why your program crashes
sometimes.
Typically most architectures return on a suitable alignment for all types
when dealing with dynamic memory. Thus four bytes are atleast consumed in
practice (even in cases of zero byte allocation). Also implementation(s)
typically use an additional 4-byte word to record allocation sizes, so then
another four bytes are consumed.Such information is typically placed right
before the dynamically allocated item.
When you allocate on multiple of 4 bytes the alignment is proper .Thus when
you try to write past the allocated boundary, you could be attempting to
overwrite basically anything. This may/may not be the same in other cases.
Ofcourse I am just proposing one explanation. An implementation can do it
any way.

HTH,
J.Schafer
 
K

Karl Heinz Buchegger

Vishal said:
Josephine,

I am sorry, if I did not ask the question clearly enough.


Yes, I know that and I am overwriting the memory intentionally. I was curious
to know, how would a typical compiler handle such a case.

The compiler doesn't handle anything in this case. What you overwrite,
and if it is vital to the whole system is more or less random and depends
on your exact program text, the state your operating system is in, if there
are other programs running, how low is the operating system on memory, etc.
Add a variable to your function and the symptoms may be different.
Yes, the behaviour
is indeed undefined according to the language standards in such a case. However,
given a combination of Operating System and Compiler, the behaviour of the
program will have an explanation and I was interested in that explanation.

The only way to figure out what really happens in your case is to look
at the assembly output and do a carefull examination and a step through
through the program and hope that the environment your program runs in has
not changed to much, such that the symptoms are different.
Maybe, this group is the wrong place to ask this question.

It is.
This group has no answer for you, because in the context of this group
there doesn't exist an answer, except: undefined behaviour - anything can happen.
 
V

Vishal Grover

I compiled this with 3.2.2 on Red Hat Linux 9 on an Intel i686. When I run the
As others have answered, the only general answer is that you're invoking
undefined behavior, where anything or nothing may happen.

In practice it seems your compiled program is overwriting some allocation
information.

Such information is typically placed right before a dynamically allocated
item. That seems to fit the alignment issue you have noted. It's no
great mystery, but it has nothing to do with C++.

This seems a reasonable explanation. Thank you.
On the topic of C++, in order of appearance in the above code:


* Guideline: don't use atoi, since it has no error checking.
Exception: where you want 0 as result in case of error (add comment).

* Guideline: don't use raw pointers and arrays, use smart pointers and
standard library containers.

* Guideline: avoid using a loop control variable after the loop.

* Guideline: always execute a corresponding 'delete' for each 'new'.

* Guideline: when you rely on the return value 'main' to indicate
failure, express success explicitly by returning EXIT_SUCCESS.

Thanks again. Will keep in mind.
Finally, Word of Advice: don't take technical comments personally and
threaten to "leave this list", as you seem to have done; see e.g.
<url:http://www.winternet.com/~mikelr/flame52.html>.

I admit, I am a newbie, and I have learnt a few things today.

Regards
Vishal
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top