-3

I'm learning Linux C programming recently,and there is a question have puzzled me long time.The question is that when we use malloc to allocate some memory,we can use the addresses that over the size we required,but when we access a large address than we required,the system may kill our process.just like the following codes:

int *p = malloc(10*sizeof(int));
*(p + 10) = 1;

when we use this clause,the system may not kill our process,but when we use:

*(p +10000) = 1;

the system may kill our process. So why does the system do it in this way?

Yu Hao
  • 119,891
  • 44
  • 235
  • 294
seabiscuitxf
  • 1
  • 1
  • 2
  • 1
    By "system killing our process" I assume you mean a [segmentation fault](http://en.wikipedia.org/wiki/Segmentation_fault) is happening? Reading past your allocated memory is in C undefined behaviour and often results in a segfault. –  Mar 19 '14 at 13:17
  • If you are unlucky `*(p+10)=1;` may crash, and it surely is corrupting your memory (since the last valid index is 9). Use [valgrind](http://valgrind.org/) – Basile Starynkevitch Mar 19 '14 at 13:18
  • actually p+10 works, as malloc isa allocating 10 int sized spaces of memory, and also leaving a pointer to the next memory address that shall be used. But that's all. So *(p+10) is there, *(p+11) onwards is not. But avoid casting data to the next memory slot malloc indicates, as they will be used by the program on the next malloc, and, in best case scenario you will lose the information (worst case, program will crash) – Inox Mar 19 '14 at 13:22
  • You might be interested in http://stackoverflow.com/questions/20312340/why-does-this-implementation-of-strlen-work (even if it's not obvious from the title) – loreb Mar 19 '14 at 13:33

4 Answers4

2

Obviously, you can only access memory you allocated upfront.

So what you're doing basically is:

int *p = malloc(10 * sizeof(int));

Here, you allocate memory for 10 ints.

*(p + 10) = 1;

This can be rewritten as (by removing pointer arithmetic):

p[10] = 1;

Now, you can clearly see that there's no memory for the 10th item. So in theory, your code should crash here already.

However, often, the OS decides to allocate a little more memory or you've allocated a block of memory next to p (in which case the OS won't intervene, even though your code doesn't work the way you want it to).


Let me give you an example:

char foo[4] = "foo";
char bar[4] = "bar";

Now (in theory, obviously it depends on what your compiler does) if you access the 5th char of foo, it actually maps to the first char of bar:

foo[5] = "c";
printf("%s %s\n", foo, bar); /* == foo car */

As I said, this depends on your compiler and I only give you this example because it might help you understand how the OS allocates memory.


One more thing:

The NULL pointer ((void *)0) is "protected" and the OS guarantees that it fails when you try to access the contents of that address.

mnme
  • 620
  • 6
  • 19
cutsoy
  • 10,127
  • 4
  • 40
  • 57
  • Your answer is not quite correct / sloppy. The reason why your program might be able to access memory you did not allocate is a consequence of C design principles / standard on the one hand and the way modern computers organize / manage memory access rights. – Michael Beer Dec 13 '19 at 00:04
  • C has the concept of 'undefined behaviour': The C standards define the behaviour of C in certain situations, but in others the standard just states: if you do this, anything might happen. Accessing memory you did not allocate, is just one of those corners: C deliberately does not specify what would happen in this case - especially it does not demand preventing your program from accessing. So whoever implemented your C compiler is free to terminate your program, blast your office, or just ignore it. – Michael Beer Dec 13 '19 at 00:17
  • On the architectural /OS level, memory is often organized in chunks of constant size - 'segments'. access rights can only be granted for an entire segment. if your architecture organized memory in segments of 16 bytes, and you allocated memory for 1 byte, internally the OS would assign your program an entire segment of 16 bytes and Mark it read/writable by your process. this your process would be able to access a chunk of 16 'around' your 1 byte allocation. Btw: if you access a segment you receive a signal 'segv' - segmentation fault. if want to know more, 'MMU' would be a good starter. – Michael Beer Dec 13 '19 at 00:26
2

Actually, you can access memory you didn't allocate.

It's not C that (sometimes) prevents you from doing so (it's designed after the philosophy that the user is always right), it's the operating system using special MMU (memory management unit) hardware.

This hardware cannot (for performance and cost reasons) secure any arbitrary address, but only ranges of memory (pages). Thus illegal (from a programmer's standpoint) accesses are sometimes possible (if they are on the same memory page where you have legally allocated memory), other illegal accesses (outside pages with legal addresses) are prevented by the MMU that issues a page fault (segmentation violation).

This obviously doesn't mean you are allowed to access unallocated memory, it just explains why you sometimes get by with it.

Of course all this is only true for platforms that actually have a MMU. There are still a lot around that haven't, so better learn your lessons ;).

mfro
  • 3,286
  • 1
  • 19
  • 28
  • Thats actually the best answer here. why hasn't it been accepted? – Michael Beer Dec 13 '19 at 00:27
  • The answer explains it well, here's a minor addition: The kernel always allocates memory in pages even if you request (using sbrk) a size which is less than a page. So lets say page size is 4096 bytes and you requested 4000 bytes, then even if you access memory at 4004 the MMU will allow it. But accessing anything after 4096 will give an illegal address error. The problem in doing this is that you may never know the page size on a particular hardware or OS. So doing this is always dangerous though not fatal everytime. – Pranshu Oct 10 '21 at 07:07
1

if you dynamically allocate memory, you are allocating it on the heap. You do this by assigning a pointer the beginning of your memory block. So you can add an offset to this pointer and access a specific memory location. If this offset is large enough your pointer could end up pointing outside of the heap, or outside of your data section, or to a protected memory location. This will cause a segmentation fault - you may be accessing a memory location which is used for something else.

Pandrei
  • 4,843
  • 3
  • 27
  • 44
  • the only thing you can rely upon is what the c standard says. and the c standard defines access to an unallocated memory as causing undefined behaviour. getting a segmentation fault reliably would be great. accessing memory you did not allocate does not reliably trigger a segv. the memory is divided into (usually fixed size) segments. the MMU grants access to an entire segment. thus if you allocate not exactly a multiple of a segment, there are chunks of memory that you never allocated but you still can access without causing a segv. – Michael Beer Jan 26 '20 at 17:25
-1

Your question is unclear, but I think you're asking why you "can" access an element outside of what you allocated. The answer is that you really can't. There's no telling what you'll be stepping on when you do that -- perhaps another variable, maybe even your code. For very large offsets, you'll definitely end up outside of the system memory that you "own", and will have your process killed.

It appears that you have no idea what you're doing with malloc(). Go back and read about it again.

Phil Perry
  • 2,126
  • 14
  • 18
  • That's too harsh. @seabiscuitxf just put a sample dummy code, not a working code of something. And that's also wrong, malloc actually leave a pointer to the next memory space. So *(p+10) is defined and can be accessed – Inox Mar 19 '14 at 13:23
  • 1
    It's not too harsh. He's deliberately attempting to access an element outside of the allocation, which means he has no idea of what he's doing. `p+10` could overwrite the next heap block pointer or something else that will cause corruption on the next malloc(). `p+10000` _might_ be not only outside the heap, but outside his addressable memory space. – Phil Perry Mar 19 '14 at 13:32
  • he's just curious about this, must have discovered it by accident. Your last comment is very useful, saying that "It appears that you have no idea what you're doing with malloc(). Go back and read about it again." is not – Inox Mar 19 '14 at 13:40
  • that is not helpful, and by any definition of 'can' that I am aware of, actually wrong. Whether you approach the question by looking at the C standard (flavor should not matter in that case), or the actual implementation of C on real machines, you can access memory, or at least, you might be able to. – Michael Beer Dec 13 '19 at 00:32