Re: why doesn't the following cause a coredump in Linux?

Darryl Miles (dlm@g7led.demon.co.uk)
Sun, 6 Jul 1997 12:57:11 +0100


In article <Pine.LNX.3.96.970705221241.9422A-100000@bibendum.3Sheep.COM> you wrote:
: The following program will not cause a coredump even though it looks like
: I am assigning a value to a illegal memory reference. Why is this?

First of all your questions would be better aired on the newsgroup
comp.os.linux.development.apps maybe even comp.unix.programmer.
The linux-kernel list is for kernel specific discussion.

Variable 'a' comes out of dynamic storage from malloc (and friends). The
memory malloc uses is allocated by the kernel to the application at 4Kb
granuality (under i386). This generally forms a contigious area of virtual
address space, all of which is legally addressable for read and write by
the application.

If 'a' = (double **)0x800010

: a[0][0]=255;

is

*((double *)0x800010) = 255;

: a[0][5]=256;

is

*((double *)(0x800010 + (5 * sizeof(double)))) = 255;

or

*((double *)0x800038) = 255;

When you called calloc() it probably asked the kernel for another 4Kb page
(because you've never called calloc before in the application so it has
until now, no memory to handout, not because all malloc requests use up a
4Kb page). It probably allocated 0x800000 to 0x801000 in the above
fictional case. Which means the application can legally address any byte
in this memory region.

So even though your memory reference is techinically out-of-bounds, it
doesn't cause a crash because the memory writes it performs are not to
illegal areas of memory.

You will probably find that if your application continuted to use malloc
(and friends) it would crash further down the line when it tried allocating
or freeing a block, or that a piece of your application data gets corrupted
and if you're really lucky you hit an area of memory not yet allocated by
malloc and also not part of mallocs internal memory management data
structures, in which case you may never know about the bug.

: Am I
: allocating more memory than I need in my dim2d or am I allocating it the
: wrong way?

No, but the underlying malloc function is allocating a little bit more than
it probably needs to, but this really makes no difference in this general
programming error, since if your application ran a bit doing more mallocs
(like programs do) then executed this code you'd still be writing over bits
of memory which it's shouldn't be.

: I am not sure why the main() references won't cause a core
: dump, since it looks like I'm poking past the array's boundaries (at least
: in the static case, one would think so).

Variable 'a2' this is automatic (not static) and storage is located on the
stack. What you'll be doing here is probably overwriting part of the
command line arguments or environment space. I think I am correct in saying
that Linux puts the command line arguments and enviroment variables onto the
stack before calling main with the count and pointers back to the stack
space to give the application argc, argv[] and environ[].

In:

a2[0][5]=256

If it were any less than 5, you'd probably start overwriting the return
address for main() (and cause a crash on the way out of main, usualy
leaving 'gdb' with a 'bracktrace' of garbage). If it were a little
less still you've be overwriting some registers saved to remember the
amount of space used by automatic variables, this shows up as a similar
result to overwriting the return address. If it were a little less
again you'd overwrite the variable 'a' until finally you get to a2[0][0]
and you'd be writing into variable 'a2'. Obviously 'a2' is 8 bytes long
(on i386) the you may only find a2[0][1] = xxx or a2[0][2] = xxx, wipes
some or all of the above out.

So the reason this doesn't crash is because you're again writing into
memory which you're legally allowed to perform a write operation on.

If you were to walk the argv[] of environ[] tables and strings before and
after access you'd probably find something got corrupted.

: --
: #include <stdio.h>
: #include <stdlib.h>

: double **dim2d(int n, int m) /* n = # of rows, m = # of columns */
: {
: int i;
: double **narr;
: narr=(double **)calloc(n, sizeof(double *));
: if (narr == NULL) return NULL;
: for (i=0; i < n; i++) {
: narr[i]=(double *)calloc(m, sizeof(double));
: if (narr[i] == NULL) return NULL;
: }
: return narr;
: }

: main()
: {
: double **a=dim2d(1,1);
: double a2[1][1];
: a[0][0]=255;
: a[0][5]=256;

: a2[0][0]=255;
: a2[0][5]=256;
: }

-- 
Darryl Miles