Why no segmentation fault

  • Thread starter Christian Christmann
  • Start date
C

Christian Christmann

Hi,

I'm wondering why this program does not crash with a segmentation
fault:

#include <malloc.h>
#include <string.h>
#include <stdio.h>

int main()
{
char *array;

array = (char*)malloc(10 * sizeof(char) );
if ( array == NULL )
exit( 0 );

strcpy( array, "11223456789\0");

printf( "\narray[11]: %c\n", array[11] )

return 0;
}

I allocate space for 10 characters on the system heap and then copy
a string of size 12 into the allocated space. Why does the program not
crash?
My understanding was so far:
malloc request some new free space on the system heap. So, first the
program memory manager is consulted to check if it is already assigned
some free space by the operating system that might be suitable for the
malloc request. If so, this memory segment is used. Otherwise, the
request is directed to the OS that provides some new free memory that
is now assigned to this program (process) and used for the malloc memory
allocation. However, when I call "strcpy( array, "11223456789\0")" I
write the first 10 characters to the allocated memory area.The
remaining 2 characters exceed the memory area I was granted access to
and are tried to be written to memory I have no write access to. That
illegal memory access should be noticed by the OS that terminates the
program with a segmentation fault.

Furthermore, my printf should also crash the program since I
illegally attempt to read from memory I have no access to.

Thank you.

Chris
 
R

Richard G. Riley

Hi,

I'm wondering why this program does not crash with a segmentation
fault:

#include <malloc.h>
#include <string.h>
#include <stdio.h>

int main()
{
char *array;

array = (char*)malloc(10 * sizeof(char) );
if ( array == NULL )
exit( 0 );

strcpy( array, "11223456789\0");

printf( "\narray[11]: %c\n", array[11] )

return 0;
}

There is no guarentee that HW will catch all such illegal memory
accesses. There are not (always) runtime checks in languages to check
for out of bounds : it is one of the efficiencies of C that it assumes
the programmer will do the necessary bounds checks. Writing over
"illegal" memory is, I believe, "undefined" but most certainly bad
practice and most certainly will lead to nasties cropping up at a
later date if nto immediately.

I velieve it is legal to reference one unit of storage past the
"malloc"ed area, but I'm sure someone will provide more info on that.
 
S

santosh

Christian said:
Hi,

I'm wondering why this program does not crash with a segmentation
fault:

#include <malloc.h>

Non-standard header. Should include stdlib.h instead.
#include <string.h>
#include <stdio.h>

int main()

A better form is int main(void)
{
char *array;

array = (char*)malloc(10 * sizeof(char) );

Don't cast the return value of malloc. A better form of the above
statement is:
array = malloc(10 * sizeof *array);

This also has the side effect that if you ever change the base type,
(char here), you won't have to modify this statement.
if ( array == NULL )
exit( 0 );

exit(EXIT_SUCCESS); or exit(EXIT_FAILURE) would be more portable though
zero is always a portable return value to indicate successfull
termination.
strcpy( array, "11223456789\0");

printf( "\narray[11]: %c\n", array[11] )

return 0;
}

I allocate space for 10 characters on the system heap and then copy
a string of size 12 into the allocated space. Why does the program not
crash?
My understanding was so far:
malloc request some new free space on the system heap. So, first the
program memory manager is consulted to check if it is already assigned
some free space by the operating system that might be suitable for the
malloc request. If so, this memory segment is used. Otherwise, the
request is directed to the OS that provides some new free memory that
is now assigned to this program (process) and used for the malloc memory
allocation. However, when I call "strcpy( array, "11223456789\0")" I
write the first 10 characters to the allocated memory area.The
remaining 2 characters exceed the memory area I was granted access to
and are tried to be written to memory I have no write access to. That
illegal memory access should be noticed by the OS that terminates the
program with a segmentation fault.

Furthermore, my printf should also crash the program since I
illegally attempt to read from memory I have no access to.

Your program writes past the end of the array and doing so, invokes
undefined behaviour. Wether it eventually crashes or not is
implementation defined. In any case, anything can happen as per the C
standard. It might apparently continue running normally, (like your
case, which could be because, your library memory manager reserved more
memory as a part of your process, and that they just happen to lie past
your allocated chunk.), or it might misbehave later or dump core
immediately.

It doesn't matter. Once you've created undefined behaviour, anything
might happen.
 
E

Eric Sosman

santosh said:
Your program writes past the end of the array and doing so, invokes
undefined behaviour. Wether it eventually crashes or not is
implementation defined. [...]

<pedantry>

It's not even implementation-defined; the implementation
has no obligation to document the consequences. Undefined is
undefined, and there's an end on't.

</pedantry>
 
S

santosh

Eric said:
santosh said:
Your program writes past the end of the array and doing so, invokes
undefined behaviour. Wether it eventually crashes or not is
implementation defined. [...]

<pedantry>
It's not even implementation-defined; the implementation
has no obligation to document the consequences. Undefined is
undefined, and there's an end on't.
</pedantry>

Thanks pedantic point duly noted and filed!
 
J

Jorgen Grahn

Christian Christmann wrote: ....

Don't cast the return value of malloc. A better form of the above
statement is:
array = malloc(10 * sizeof *array);

This also has the side effect that if you ever change the base type,
(char here), you won't have to modify this statement.

Yes; casting malloc()'s return value became obsolete when void * was
introduced, some twenty years ago.

As a side note, typing "sizeof(char)" is pointless, since its value is, by
definition, 1.

/Jorgen
 
K

Keith Thompson

santosh said:
Christian Christmann wrote: [...]
This also has the side effect that if you ever change the base type,
(char here), you won't have to modify this statement.
if ( array == NULL )
exit( 0 );

exit(EXIT_SUCCESS); or exit(EXIT_FAILURE) would be more portable though
zero is always a portable return value to indicate successfull
termination.

exit(0) is exactly as portable as exit(EXIT_SUCCESS); both are defined
to return a status that indicates successful termination (though not
necessarily the same status).

But since this particular exit() is executed only on a failure of
malloc(), exit(EXIT_FAILURE) would make more sense. (Note that
exit(1), unlike exit(0), is *not* portable.)
 
S

santosh

Keith said:
"santosh" <[email protected]> writes:

exit(0) is exactly as portable as exit(EXIT_SUCCESS); both are defined
to return a status that indicates successful termination (though not
necessarily the same status).

Err, don't you mean:
"...though not necessarily the same value."
above?

<snip>
 
K

Keith Thompson

santosh said:
Err, don't you mean:
"...though not necessarily the same value."
above?

No, I meant status. It's also true that it's not necessarily the same
value.

The standard says:

Finally, control is returned to the host environment. If the
value of status is zero or EXIT_SUCCESS, an implementation-defined
form of the status _successful termination_ is returned. If the
value of status is EXIT_FAILURE, an implementation-defined form of
the status _unsuccessful termination_ is returned. Otherwise the
status returned is implementation-defined.

EXIT_SUCCESS, EXIT_FAILURE, and 0 are values of type int that can be
passed to the exit() function. A "status" is a vaguely-defined thing
that's seen by the host environment; it isn't necessarily a value,
particularly an int value, in the sense used within a C program. (The
fact that parameter to exit() is also called "status" is potentially
confusing.)

If EXIT_SUCCESS==0, then presumably both exit(EXIT_SUCCESS) and
exit(0) return the same "status" to the environment. If
EXIT_SUCCESS!=0, then exit(EXIT_SUCCESS) and exit(0) may or may not
return the same "status" to the environment.
 
F

Flash Gordon

santosh said:
Christian Christmann wrote:


exit(EXIT_SUCCESS); or exit(EXIT_FAILURE) would be more portable though
zero is always a portable return value to indicate successfull
termination.

<snip>

As well as the comments others have made, exit(EXIT_SUCCESS) and
exit(EXIT_FAILURE) are no more portable than exit(0) since all three are
completely portable. Any other value and zero and I would have agreed.
However, in this case exit(EXIT_FAILURE) would have been far better
style since the program has failed.
 
F

Flash Gordon

Richard G. Riley wrote:

I velieve it is legal to reference one unit of storage past the
"malloc"ed area, but I'm sure someone will provide more info on that.

It is legal to create a pointer to one past the end, but it is not legal
to dereference that pointer.
 
S

santosh

Keith said:
No, I meant status. It's also true that it's not necessarily the same
value.
.... snip ...
If EXIT_SUCCESS==0, then presumably both exit(EXIT_SUCCESS) and
exit(0) return the same "status" to the environment. If
EXIT_SUCCESS!=0, then exit(EXIT_SUCCESS) and exit(0) may or may not
return the same "status" to the environment.

Okay, so both exit(0) and exit(EXIT_SUCCESS) need not return the same
"status" to the host environment although they both *indicate*
successful program termination. Got it now, just that your wording in
your first reply to me seemed contradictory.
 
S

santosh

Keith said:
No, I meant status. It's also true that it's not necessarily the same
value.
.... snip ...

Would it not be absurd for an implementation to return "status" values
of different kinds for exit(0) and exit(EXIT_SUCCESS), though the
standard does not disallow it? I mean, since both forms of exit() are
semantically identical, what would be gained in returning different
kinds of "status" values to the host environment? Are you aware of any
actual implementations that do this?
 
K

Keith Thompson

Flash Gordon said:
Richard G. Riley wrote:



It is legal to create a pointer to one past the end, but it is not
legal to dereference that pointer.

"not legal" meaning that it invokes undefined behavior (the
implementation is not required to diagnose it).
 
S

Stephen Sprunk

Christian Christmann said:
I'm wondering why this program does not crash with a segmentation
fault: ....
Furthermore, my printf should also crash the program since I
illegally attempt to read from memory I have no access to.

Your program invokes undefined behavior. Undefined behavior can take many
forms, including doing nothing or doing exactly what the programmer
mistakenly expects.

Just because your machine traps on some undefined operations does not mean
it always will.

S

--
Stephen Sprunk "Stupid people surround themselves with smart
CCIE #3723 people. Smart people surround themselves with
K5SSS smart people who disagree with them." --Aaron Sorkin

*** Free account sponsored by SecureIX.com ***
*** Encrypt your Internet usage with a free VPN account from http://www.SecureIX.com ***
 
K

Keith Thompson

santosh said:
... snip ...

Would it not be absurd for an implementation to return "status" values
of different kinds for exit(0) and exit(EXIT_SUCCESS), though the
standard does not disallow it? I mean, since both forms of exit() are
semantically identical, what would be gained in returning different
kinds of "status" values to the host environment? Are you aware of any
actual implementations that do this?

I suppose it would be absurd, but it would be perfectly valid. No, I
don't know of any implementations that do this. VMS is the obvious
candidate, but it defines EXIT_SUCCESS as 0, at least in the version I
have access to.
 
M

Mark

Hi,

I'm wondering why this program does not crash with a segmentation fault:

#include <malloc.h>
#include <string.h>
#include <stdio.h>

int main()
{
char *array;

array = (char*)malloc(10 * sizeof(char) ); if ( array == NULL )
exit( 0 );

strcpy( array, "11223456789\0");

printf( "\narray[11]: %c\n", array[11] )

return 0;
}

I allocate space for 10 characters on the system heap and then copy a
string of size 12 into the allocated space. Why does the program not
crash?
My understanding was so far:
malloc request some new free space on the system heap. So, first the
program memory manager is consulted to check if it is already assigned
some free space by the operating system that might be suitable for the
malloc request. If so, this memory segment is used. Otherwise, the
request is directed to the OS that provides some new free memory that is
now assigned to this program (process) and used for the malloc memory
allocation. However, when I call "strcpy( array, "11223456789\0")" I
write the first 10 characters to the allocated memory area.The remaining
2 characters exceed the memory area I was granted access to and are
tried to be written to memory I have no write access to. That illegal
memory access should be noticed by the OS that terminates the program
with a segmentation fault.

Furthermore, my printf should also crash the program since I illegally
attempt to read from memory I have no access to.
Your malloc prolly allocates (multiples of) a fixed size block (a page?)
at a time from the OS from which it gives you a piece at a time every time
you malloc. If you've malloced it all up malloc will ask the OS for
more.... This is more efficient then having to ask the OS every time you
malloc a byte.

So even though you didn't get the memory from malloc, as long as you stay
inside the memory malloc allocated from the OS you wont cause a
segfault. The OS will happily let you ****-up, as long a you do it in
your own home/process :)

Mark.
 
M

Mark McIntyre

Would it not be absurd for an implementation to return "status" values
of different kinds for exit(0) and exit(EXIT_SUCCESS), though the
standard does not disallow it?

There are different kinds of success, though, aren't there?
I mean, since both forms of exit() are
semantically identical, what would be gained in returning different
kinds of "status" values to the host environment?

eg
exit (success-and-missed-object-in-water)
exit (success-and-beached-on-iceberg)
exit(success-but-ship-sank-anyway-due-to-outside-factors)
Are you aware of any
actual implementations that do this?

I strongly suspect VMS lets you have a forest of possible different
"it worked" results.
0 = VMS-I-SUCCESS successful programme termination
64 = VMS-I-SUCCESS successful cluster shutdown
128 = VMS-I-SUCCESS successfully ejected the warp core
:)

Mark McIntyre
 
K

Keith Thompson

Mark McIntyre said:
There are different kinds of success, though, aren't there?

Maybe. Some systems define only one kind of success (corresponding to
exit(0)).

[snip]
I strongly suspect VMS lets you have a forest of possible different
"it worked" results.
0 = VMS-I-SUCCESS successful programme termination
64 = VMS-I-SUCCESS successful cluster shutdown
128 = VMS-I-SUCCESS successfully ejected the warp core
:)

Actually, odd values denote success and even values denote errors
(which is why VMS has to translate exit(0) into a failure indication,
and exit(1) actually denotes success). But yes, there are many
different kinds of both success and failure in VMS (but no portable
way to specify them in C).
 
M

Mark McIntyre

Actually, odd values denote success and even values denote errors
(which is why VMS has to translate exit(0) into a failure indication,
and exit(1) actually denotes success).

I think you may have this backwards, since I recall being able to
compile perfectly normal C code with VAX-C, but its at least five
years since I last programmed on a Vax so...

Mark McIntyre
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top