David Černý
David Černý

Reputation: 112

strcpy working no matter the malloc size?

I'm currently learning C programming and since I'm a python programmer, I'm not entirely sure about the inner workings of C. I just stumbled upon a really weird thing.

void test_realloc(){
  // So this is the original place allocated for my string
  char * curr_token = malloc(2*sizeof(char));

  // This is really weird because I only allocated 2x char size in bytes 
  strcpy(curr_token, "Davi");
  curr_token[4] = 'd';
  // I guess is somehow overwrote data outside the allocated memory?
  // I was hoping this would result in an exception ( I guess not? )      

  printf("Current token > %s\n", curr_token);

  // Looks like it's still printable, wtf???
  char *new_token = realloc(curr_token, 6);
  curr_token = new_token;
  printf("Current token > %s\n", curr_token);
}


int main(){
  test_realloc();
  return 0;
}

So the question is: how come I'm able to write more chars into a string than is its allocated size? I know I'm supposed to handle mallocated memory myself but does it mean there is no indication that something is wrong when I write outside the designated memory?

What I was trying to accomplish

  1. Allocate a 4 char ( + null char ) string where I would write 4 chars of my name
  2. Reallocate memory to acomodate the last character of my name

Upvotes: 2

Views: 489

Answers (4)

Vlad from Moscow
Vlad from Moscow

Reputation: 310980

Usually malloc is implemented such a way that it allocates chunks of memory aligned to paragraph (fundamental alignment) that is equal to 16 bytes.

So when you request to allocate for example 2 bytes malloc actually allocates 16 bytes. This allows to use the same chunk of memory when realloc is called.

According to the C Standard (7.22.3 Memory management functions)

  1. ...The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement and then used to access such an object or an array of such objects in the space allocated (until the space is explicitly deallocated).

Nevertheless you should not rely on such behavior because it is not normative and as result is considered as undefined behavior.

Upvotes: 1

davmac
davmac

Reputation: 20631

know I'm supposed to handle mallocated memory myself but does it mean there is no indication that something is wrong when I write outside the designated memory?

Welcome to C programming :). In general, this is correct: you can do something wrong and receive no immediate feedback that was the case. In some cases, indeed, you can do something wrong and never see a problem at runtime. In other cases, however, you'll see crashes or other behaviour that doesn't make sense to you.

The key term is undefined behavior. This is a concept that you should become familiar with if you continue programming in C. It means just like it sounds: if your program violates certain rules, the behaviour is undefined - it might do what you want, it might crash, it might do something different. Even worse, it might do what you want most of the time, but just occasionally do something different.

It is this mechanism which allows C programs to be fast - since they don't at runtime do a lot of the checks that you may be used to from Python - but it also makes C dangerous. It's easy to write incorrect code and be unaware of it; then later make a subtle change elsewhere, or use a different compiler or operating system, and the code will no longer function as you wanted. In some cases this can lead to security vulnerabilities, since unwanted behavior may be exploitable.

Upvotes: 7

surendra nath
surendra nath

Reputation: 339

Suppose that you have an array as shown below.

int arr[5] = {6,7,8,9,10};

From the basics of arrays, name of the array is a pointer pointing to the base element of the array. Here, arr is the name of the array, which is a pointer, pointing to the base element, which is 6. Hence,*arr, literally, *(arr+0) gives you 6 as the output and *(arr+1) gives you 7 and so on. Here, size of the array is 5 integer elements. Now, try accessing the 10th element, though the size of the array is 5 integers. arr[10]. This is not going to give you an error, rather gives you some garbage value. As arr is just a pointer, the dereference is done as arr+0,arr+1,arr+2and so on. In the same manner, you can access arr+10 also using the base array pointer. Now, try understanding your context with this example. Though you have allocated memory only for 2 bytes for character, you can access memory beyond the two bytes allocated using the pointer. Hence, it is not throwing you an error. On the other hand, you are able to predict the output on your machine. But it is not guaranteed that you can predict the output on another machine (May be the memory you are allocating on your machine is filled with zeros and may be those particular memory locations are being used for the first time ever!). In the statement, char *new_token = realloc(curr_token, 6); note that you are reallocating the memory for 6 bytes of data pointed by curr_token pointer to the new_tokenpointer. Now, the initial size of new_token will be 6 bytes.

Upvotes: 2

Luca Di Liello
Luca Di Liello

Reputation: 1643

No automatic bounds checking is performed in C. The program behaviour is unpredictable. If you go writing in the memory reserved for another process, you will end with a Segmentation fault, otherwise you will only corrupt data, ecc...

Upvotes: 0

Related Questions