0

I've been doing a bit of testing on some code I wrote when I noticed that I had a huge mistake in my code regarding array sizes, yet the program still ran fine. Here's some simplified code to give you an idea of what's going on.

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>

typedef struct
{
int score;
}player;

void printScore(player *p, int num);

int main(void)
{

    printf ("\nEnter number of players (1 - 4)\n");
    scanf ("%d", &numPlayers);

    player *p = (player*)malloc(sizeof(player) * 3);

    for (i=0;i<numPlayers;i++)
    {
        printScore(p, i);
    }

}

void printScore(player *p, int num)
{

        p[num].score = 1;
        printf ("%d\n", p[num].score);
}

The 3 in the malloc function should actually be numPlayers. If I leave it at 3, and enter a higher number in the menu, the program will usually crash, but it does work sometimes. How is that possible? If I've only enough memory reserved for p[0], p[1], p[2], how does (for example) p[15].score even exist to be populated?

karoma
  • 1,548
  • 5
  • 24
  • 43
  • 1
    Possible duplicate: http://stackoverflow.com/questions/8641478/invalid-read-write-sometimes-creates-segmentation-fault-and-sometimes-does-not/ – Dan Fego Mar 12 '12 at 00:52
  • What are you compiling with? Some compilers will ensure that behaviour like this will cause a crash *all* the time. – detly Mar 12 '12 at 01:27

4 Answers4

1

It's called "undefined behavior". When the behavior is undefined - everything is possible. Accessing invalid pointer (as in your example) is one of many cases in which the behavior of the program is undefined by the standard, and the compiler is free to do whatever it wishes.

Any behavior is the correct behavior in such case. In your case the compiler just doesn't do anything, and the program runs as if the memory was allocated. If the OS doesn't kill you for that (= program crashes on access violation) - that's your pure luck.

littleadv
  • 20,100
  • 2
  • 36
  • 50
0

In C code, you should remember you are manipulating the real memory, the compiler won't help you to check invalid memory access.

p is a pointer on heap, p has length 3*sizeof(player), but after that, the memory may still exist, but the value is unpredictable.

ciphor
  • 8,018
  • 11
  • 53
  • 70
0

In C reserving memory is exactly that -- a reservation. It does not place a limit on what is actually allocated, it only guarantees that the space that you have requested was reserved for your usage. You program starts reading what is rightfully yours and then continues reading the contents of memory that you have no right to access. The memory manager is likely going to let you keep reading memory. C doesn't protect you from doing this. It is up to you to know what you have allocated and what you are allowed to read.

As others will likely say, reading off of the end of allocated space is undefined behavior which means anything can happen. In most cases, quite reasonable things occur which is what you are seeing here.

D.Shawley
  • 58,213
  • 10
  • 98
  • 113
0

Program map in memory can be organized for example: (text+data+bss)

This map is established at compile time and and remains constant during execution, your program can expand into the unoccupied portion of virtual memory at runtime when using dynamic allocation malloc().

Your program: 1- At run time it allocates 3 memory segments in the memory (HEAP).

2- p is initialized by malloc with an address NNNN in the heap. It's the location of first set of the 3 segments allocated. The first address (p+0*(sizeof(player)), the second set will at (p+1*(sizeof(player)) and the third one at (p+2*(sizeof(player)).

With C you can try to access where ever you want but it's to you to instal safety mechanisms for not corrupting your code, your data or some non protected zone. Example of safety mechanism in this case: use numPlayers*sizeof instead of a constant "3" in 3*sizeof or test user's input.

So any read/write access to p[15] will be directed to (p+15*(sizeof(player))).

3- Why is it populated ? Memory may contains other data from your program or just noise. That's what populate your structure fields.

4- Why it's a random crash ? Your write access will corrupt data but it may not be bad enough to crash. If you go down in memory toward the TEXT segment. You will corrupt your code and you will crash for sure.

Alf
  • 1
  • 1