This question already has answers here:
How dangerous is it to access an array out of bounds?
(12 answers)
Closed 4 years ago.
#include<stdio.h>
#include <stdlib.h>
int *ip_range ;
int main()
{
ip_range = (int *) malloc(1);
ip_range[0]=2;
ip_range[10]=2;
ip_range[20]=2;
ip_range[33787]=12444;
printf("%d\n", ip_range[33787]);
}
I have malloc just 1 block then why it is accessible till 33787 and generating core on 33788.
You are writing to memory which you do now own i.e. was not handed back by malloc , calloc or realloc. This results in undefined behaviour. Your program can do anything at all, including not producing any error message or core dump.
It is undefined behaviour because you are trying to access memory out of bound. C does not check memory bound.
According to cppreference :
undefined behavior - there are no restrictions on the behavior of the program. Examples of undefined behavior are memory accesses
outside of array bounds, signed integer overflow, null pointer
dereference, modification of the same scalar more than once in an
expression without sequence points, access to an object through a
pointer of a different type, etc.
Related
This question already has answers here:
(Why) is using an uninitialized variable undefined behavior?
(7 answers)
Closed 3 years ago.
if i run this program:
#include <stdio.h>
int main()
{
int a=32,b=2,c,i;
for(i=0;i<3;i++){
printf("%d\n",c);
c=a/b;
a=c;
}
return 0;
}
the output is:
32765
16
8
In there, I dont define the value of C, Where from came this output 32765.?
even again i run this code more time,it show different values like 32764,32767. Why this different output showing on?
Because c has automatic storage duration (i.e. is a non-static local variable) and is uninitialized, its value is indeterminate. Attempting to print an uninitialized variable that never had its address taken (i.e. was not the subject of the address-of operator &) invokes undefined behavior.
Even if you did take the address of c you could still have undefined behavior if it contains a trap representation. If it does not contain a trap representation (and most implementations don't have them), the the value is unspecified which simply means the printed value can't be predicted.
Automatic variables (a local variables which are allocated and deallocated automatically when program flow enters and leaves the variables's scope) for which there is no explicit initializer have undefined (i.e. garbage) values.
This question already has answers here:
How dangerous is it to access an array out of bounds?
(12 answers)
Writing to pointer out of bounds after malloc() not causing error
(7 answers)
Why is it that we can write outside of bounds in C?
(7 answers)
What happens if I try to access memory beyond a malloc()'d region?
(5 answers)
Why does int pointer '++' increment by 4 rather than 1?
(5 answers)
Closed 3 years ago.
I've been digging into memory allocation and pointers in C. I was under the impression that if you do not allocate enough memory for a value and then try to put that value in that memory cell, the program would either crash or behave incorrectly.
But what I get is a seemingly correct output where I'd expect something else.
#include <stdio.h>
#include <stdlib.h>
int main()
{
// Here we intentionally allocate only 1 byte,
// even though an `int` takes up 4 bytes
int * address = malloc(1);
address[0] = 16777215; // this value surely takes more than 3 bytes. It cannot fit 1 byte.
address[1] = 1337; // just for demo, let's put a random other number in the next memory cell.
printf("%i\n", address[0]); // Prints 16777215. How?! Didn't we overwrite a part of the number?
return 0;
}
Why does this work? Does malloc actually allocate more than the number of bytes that we pass to it?
EDIT
Thanks for the comments! But I wish to note that being able to write to unassigned memory is not the part that surprises me and it's not part of the question. I know that writing out of bounds is possible and it is "undefined behavior".
For me, the unexpected part is that the line address[1] = 1337; does not in any way corrupt the int value at address[0].
It seems that the explanations for this diverge, too.
#Mini suggests that the reason for this is that malloc actually allocates more than what's passed, because of cross-platform differences.
#P__J__ in the comments says that address[1] for some reason points to the next sizeof(int) byte, not to the next byte. But I don't think I understand what controls this behavior then, because malloc doesn't seem to know about what types we will put into the allocated blocks.
EDIT 2
So thanks to the comments, I believe I understand the program behavior now.
The answer lies in the pointer arithmetic. The program "knows" that an address pointer is of type int, and therefore adding 1 to it (or accessing via address[1]) gives an address of the block that lies 4 (sizeof(int)) bytes ahead.
And if we really wanted, we could move just one byte and really corrupt the value at address[0] by coercing address to char * as described in this answer
Thanks to all and to #P__J__ and #Blastfurnace in particular!
malloc often allocates more than you actually ask for (all system/environment/OS dependent), which is why it works in you scenario (sometimes). However, this is still undefined behavior it can actually allocate only 1 byte (and you are writing to what may not be allocated heap memory).
C doesn't mandate any kinds of bounds checking on array accesses, and it's possible to overflow storage and write into memory you don't technically own. As long as you don't clobber anything "important", your code will appear to work as intended.
However, the behavior on buffer overruns is undefined, so the results will not generally be predictable or repeatable.
This question already has answers here:
How dangerous is it to access an array out of bounds?
(12 answers)
Closed 5 years ago.
I'm initializing a void pointer with 1 byte of memory and typecasting it to a int pointer and dereferencing it giving it a value 3(which needs 4 bytes) but it is running fine. Shouldn't this result in an error or cause a runtime exception like OOM?
void* record = malloc(1);
int i=3;
*((int*)record) = 3;
When you write past the end of a memory block allocated by malloc as you've done here, you invoke undefined behavior.
Undefined behavior means the behavior of the program can't be predicted. It could crash, it could output strange results, or it could appear to work properly. Also, a seemingly unrelated change such as adding an unused local variable or a call to printf for debugging can change the way undefined behavior manifests itself.
To summarize, with undefined behavior, just because the program could crash doesn't mean it will.
This question already has answers here:
Writing more characters than malloced. Why does it not fail?
(9 answers)
Why don't I get a segmentation fault when I write beyond the end of an array?
(4 answers)
Closed 6 years ago.
I was writing some code and I used the function calloc.
I understand that, when the first and the second arguments passed to this function are both zero, the function is going to alloc the necessary space for 0 elements, each of them with size 0, but here is the strange thing.
This program works fine even if n > 0. Why is that happening? I think it should display an error because I'm trying to write in a position of the array that doesn't exist. Thanks!
#include <stdio.h>
#include <stdlib.h>
int main(){
int n;
scanf("%d", &n);
int *test = calloc(0, 0);
for(int i = 0; i < n; i++){
test[i] = 100;
printf("%d ", test[i]);
}
return 0;
}
In C, a lot of wrong and "wrong" things don't display error messages from the compiler. In fact, you may not even see error messagens when you run the program -- but another person running your program in a different computer may see the error.
One important concept in C is called undefined behavior. To put it in simple terms, it means that the behavior of your program is unpredictable, but you can read more about this subject in this question: Undefined, unspecified and implementation-defined behavior.
Your program is undefined for a two reasons:
When either size or nmemb is zero, calloc() may return NULL. Your program is not checking the output of calloc(), so there's a good chance that when you do test[i] you are attempting to derreference a NULL pointer -- you should always check the result of calloc() and malloc().
When you call malloc() or calloc(), you are essentialy allocating dynamic memory for an array. You can use your pointer to access the elements of the array. But you can't access anything past the array. That is, if you allocate n elements you should not try to access the n+1-th element -- nether for reading.
Both items above make your program invoke undefined behavior. There might also be something undefined about accessing an empty object other than item #2 listed above, but I'm unsure.
You should always be careful about undefined behavior because, when your program invokes UB, it is essentialy unpredictable. You could see a compilation error, the program could give an error messagen, it could run successfuly without any problems or it could wipe out every single file in your hard disk.
This question already has answers here:
I want this to crash, but it doesn't
(4 answers)
Closed 7 years ago.
#include<stdio.h>
#include<stdlib.h>
int main()
{
int *a[10];
a[2] = (int*)malloc(sizeof(int));
a[2][3]=4;
printf("%d", a[2][3]);
return 0;
}
I have given only the memory equivalent of a single int to the pointer variable. How is that I am able to access an element at index 3 for that pointer of a single int?
That's because nothing is preventing you accessing arrays out of bound and this invokes undefined behavior. Any expected or unexpected behavior of program can be seen.
You can try but the behaviour of your program will be undefined.
C does not perform that kind of checking at runtime.
You're accessing some randomly set RAM element. This is a common C programming mistake and is one of the reason for many security flaws.
The Heartbleed bug would be a nice example, where people were able to read a good portion of the server RAM, by accessing elements outside of the array structure.