This question already has answers here:
Why don't I get a segmentation fault when I write beyond the end of an array?
(4 answers)
Closed 7 years ago.
I'm actually learning C and I got a "problem".
I created a pointer to a structure with a char* and int with malloc(1).
The pointer works and I can edit structure children without problems.
I also created a pointer to a int (still with malloc(1)) and it works. Another thing is I didn't get core dump error when I tried to access *(pointer + 33780) (Core dump comes when the value is a bit higher) it worked, but default value was 0.
Thank you, that's not a "problem" but I'd like to know why is that doing like this.
Sorry for being the English's murderer.
EDIT : Here the code
struct Personne
{
char *name;
int age;
};
int main(int argc, char *argv[])
{
printf("%ld\n", sizeof(struct Personne));
struct Personne *testPoint = malloc(1);
printf("testPoint : %p\n", testPoint);
printf("testPoint : %p\n", testPoint->name);
testPoint->name = "UnNomInconnu";
testPoint->age = 20;
free(testPoint);
return 0;
}
Actually function malloc does not allocate a memory extent exactly of the size of 1 byte or of a similar small value. Usually the minimum size of an allocated extent is equal to the size of the paragraph that is to 16 bytes.
So if you will write for example
char *p = malloc( 1 );
then the actual size of the allocated extent can be equal to 16 bytes.
Nevertheles you should not rely on this feature becuase in general that is according to the C Standard this is undefined behaviour.
struct Personne *testPoint = malloc(1);
puts you into the realm of undefined behavior. Unfortunately UB can include "the program runs correctly in all test environments but fails in production at worst possible time" - and frequently does.
If you are on linux run your program under valgrind and/or electric fence. You will see why those tools exist.
You need:
struct Personne *testPoint = malloc(sizeof(*testPoint));
1 byte is not enough memory for your structure. The meaning of malloc() argument is the number of bytes. However, malloc() does not necessarily protect the memory beyond the allocated segment, so in some cases it is possible to overwrite the boundary without fatal consequences.
Related
This question already has answers here:
Writing to pointer out of bounds after malloc() not causing error
(7 answers)
Closed 2 years ago.
Malloc function in C allocates the size of memory passed into it's argument in bytes.
Here my struct variable has two integer values.So size of struct should be 8 bytes. I am only allocating 1 bytes and it's still working.
Why?
C (gcc)
#include <stdio.h>
#include <stdlib.h>
struct node{
int a;
int b;
}ab;
int main(){
struct node * nl=(struct node *)malloc(1); //I am allocating memory here
nl->b=89;
nl->a=45;
printf("%d %d %ld",nl->a,nl->b,sizeof(int));
}
Try it online!
When you write past the end of allocated memory, you invoke undefined behavior, which means you can't reliably predict what the program will do. It could crash, it could output strange results, or (as in this case) it can appear to work properly.
How undefined behavior manifests itself can change by making a seemingly unrelated change, such as adding an unused local variable or adding a call to printf for debugging. It could also change by compiling with different optimization settings or with a different compiler.
Just because the program could crash doesn't mean it will.
On most architectures, memory is allocated in 4k "pages" and no smaller. Malloc is placing your single requested byte somewhere in either one of these pages or just beyond the program break.
As long as you don't write beyond the allocated page, the virtual memory system is unaware of your transgression and won't segfault you. Of course, there's no way of knowing if or when an illegal access will happen, and thus in the C standard this behavior is undefined.
As part of our training in the Academy of Programming Languages, we also learned C. During the test, we encountered the question of what the program output would be:
#include <stdio.h>
#include <string.h>
int main(){
char str[] = "hmmmm..";
const char * const ptr1[] = {"to be","or not to be","that is the question"};
char *ptr2 = "that is the qusetion";
(&ptr2)[3] = str;
strcpy(str,"(Hamlet)");
for (int i = 0; i < sizeof(ptr1)/sizeof(*ptr1); ++i){
printf("%s ", ptr1[i]);
}
printf("\n");
return 0;
}
Later, after examining the answers, it became clear that the cell (& ptr2)[3] was identical to the memory cell in &ptr1[2], so the output of the program is: to be or not to be (Hamlet)
My question is, is it possible to know, only by written code in the notebook, without checking any compiler, that a certain pointer (or all variables in general) follow or precede other variables in memory?
Note, I do not mean array variables, so all the elements in the array must be in sequence.
In this statement:
(&ptr2)[3] = str;
ptr2 was defined with char *ptr2 inside main. With this definition, the compiler is responsible for providing storage for ptr2. The compiler is allowed to use whatever storage it wants for this—it could be before ptr1, it could be after ptr1, it could be close, it could be far away.
Then &ptr2 takes the address of ptr2. This is allowed, but we do not know where that address will be in relation to ptr1 or anything else, because the compiler is allowed to use whatever storage it wants.
Since ptr2 is a char *, &ptr2 is a pointer to char *, also known as char **.
Then (&ptr2)[3] attempts to refer to element 3 of an array of char * that is at &ptr2. But there is no array there in C’s model of computation. There is just one char * there. When you try to refer to element of 3 of an array when there is no element 3 of an array, the behavior is not defined by the C standard.
Thus, this code is a bad example. It appears the test author misunderstood C, and this code does not illustrate what was intended.
char *ptr2 = some initializer;
(&ptr2)[3] = str;
When you evaluate &ptr2, you obtain the address of memory where is stored the pointer that points to that initializer.
When you do (&ptr2)[3]=something you try to write 3*sizeof(void*) locations further from the location of ptr2, the address of a string. This is invalid and almost sure it finishes with segmentation fault.
No, it's not possible and no such assumptions can be made.
By writing outside a variable's space, this code invokes undefined behavior, it's basically "illegal" and anything can happen when you run it. The C language specification says nothing about variables being allocated on a stack in some particular order that you can exploit, it does however say that accessing random memory is undefined behavior.
Basically this code is pretty horrible and should never be used, even less so in a teaching environment. It makes me sad, how people mis-understand C and still teach it to others. :/
A program usually is loaded in memory with this structure:
Stack, Mmap'ed files, Heap, BSS (uninitialized static variables), Data segment (Initialized static variables) and Text (Compiled code)
You can learn more here:
https://manybutfinite.com/post/anatomy-of-a-program-in-memory/
Depending on how you declare the variable it will go to one of the places said before.
The compiler will arrange the BSS and Data segment variables as he wishes on compilation time so usually no chance. Neither heap vars (the OS will get the memory block that fits better the space allocated)
In the stack (which is a LIFO structure) the variables are put one over eachother so if you have:
int a = 5;
int b = 10;
You can say that a and b will be placed one following the other. So, in this case you can tell.
There is another exception and that is if the variable is an structure or an array, they are always placed like i said before, each one following the last.
In your code ptr1 is an array of arrays of chars so it will follow the exception i said.
In fact, do the following exercise:
#include <stdio.h>
#include <string.h>
int main(){
const char * const ptr1[] = {"to be","or not to be","that is the question"};
for (int i = 0; i < 3; i++) {
for (int j = 0; j < strlen(ptr1[i]); j++)
printf("%p -> %c\n", &ptr1[i][j], ptr1[i][j]);
printf("\n");
}
}
and you will see the memory address and its content!
Have a nice day.
This question already has answers here:
Array index out of bound behavior
(10 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 am trying to implement a simple sieve and to my help I found the following code:
int main(int argc, char *argv[])
{
int *array, n=10;
array =(int *)malloc(sizeof(int));
sieve(array,n);
return 0;
}
void sieve(int *a, int n)
{
int i=0, j=0;
for(i=2; i<=n; i++) {
a[i] = 1;
}
...
For some reason this works, but I think it should not! The space that is allocated for the variable array is only enough to support one integer, but a[i] for i = 2...10 are called in the function sieve. Shouldn't this cause problems?
I tried to change the implementation to
int array[10], n = 10;
which caused "Abort trap: 6" on runtime. However, this I understand since array[10] will be outside of the space allocated. But shouldn't the same be true also for the code where malloc i used?
Truly confusing.
You are correct in some ways. For example this line:
array =(int *)malloc(sizeof(int));
only allocates space for one integer, not 10. It should be:
array =(int *)malloc(sizeof(int) * 10);
However, that does not mean the code will fail. At least not immediately. When you get back a pointer from malloc and then start writing beyond the bounds of what you have allocated, you might be corrupting something in memory.
Perhaps you are writing over a structure that malloc uses to keep track of what it was asked for, perhaps you are writing over someone else's memory allocation. Perhaps nothing at all - malloc usually allocates more than it is asked for in order to keep the chunks it gives out manageable.
If you want something to crash, you usually have to scribble beyond an operating system page boundary. If you are using Windows or Linux or whatever, the OS will give you (or malloc in this case) some memory in a set of block, usually 4096 bytes in size. If you scribble within that block, the operating system will not care. If you go outside it, you will cause a page fault and the operating system will usually destroy your process.
It was much more fun in the days of MS-DOS. This was not a "protected mode" operating system - it did not have hardware enforced page boundaries like Windows or Linux. Scribbling beyond your area could do anything!
This question already has answers here:
Segmentation Fault - declare and init array in C
(3 answers)
Closed 8 years ago.
I have a query about using the memcpy() function.I have written the below program, it compiles but doesn't print an output. The .exe opens and the crashes. I am using Code Blocks as my IDE using GNU GCC compiler.
int main()
{
char a[]= "This is my test";
char *b;
memcpy(b,a,strlen(a)+1);
printf("After copy =%s\n",b);
return(0);
}
However, if I change the array *b to b[50] it works!! I don't understand why.
Please provide your suggestions!
Thanks!
Your pointer b is uninitialized. It is pointing to some random location in memory. So when you copy stuff into the memory which b is pointing to, bad things are likely to happen.
You need to initialize it; perhaps allocate some memory for it with malloc().
char *b = malloc(strlen(a) + 1);
And then free it when you're finished.
free(b);
You are lucky it did not crash when you used pointer - it should have.
When you copy memory, destination must be allocated first. If you use char b[50], you allocate 50 bytes for b on stack. If you use char *b, you did not allocate anything yet, and typically should do this using something like malloc : b = malloc(50);.
With malloc it will work, but then you should not forget to release that memory with free(b);.
If memory was allocated on stack, release happens automatically.
I was writing a code using malloc for something and then faced a issue so i wrote a test code which actually sums up the whole confusion which is below::
# include <stdio.h>
# include <stdlib.h>
# include <error.h>
int main()
{
int *p = NULL;
void *t = NULL;
unsigned short *d = NULL;
t = malloc(2);
if(t == NULL) perror("\n ERROR:");
printf("\nSHORT:%d\n",sizeof(short));
d =t;
(*d) = 65536;
p = t;
*p = 65536;
printf("\nP:%p: D:%p:\n",p,d);
printf("\nVAL_P:%d ## VAL_D:%d\n",(*p),(*d));
return 0;
}
Output:: abhi#ubuntu:~/Desktop/ad/A1/CC$ ./test
SHORT:2
P:0x9512008: D:0x9512008:
VAL_P:65536 ## VAL_D:0
I am allocating 2 bytes of memory using malloc. Malloc which returns a void * pointer is stored in a void* pointer 't'.
Then after that 2 pointers are declared p - integer type and d - of short type. then i assigned t to both of them*(p =t and d=t)* that means both d & p are pointing to same mem location on heap.
on trying to save 65536(2^16) to (*d) i get warning that large int value is truncated which is as expected.
Now i again saved 65536(2^16) to (*p) which did not caused any warning.
*On printing both (*p) and (d) i got different values (though each correct for there own defined pointer type).
My question are:
Though i have allocated 2 bytes(i.e 16 bits) of heap mem using malloc how am i able to save 65536 in those two bytes(by using (p) which is a pointer of integer type).??
i have a feeling that the cause of this is automatic type converion of void to int* pointer (in p =t) so is it that assigning t to p leads to access to memory regions outside of what is allocated through malloc . ??.
Even though all this is happening how the hell derefrencing the same memory region through (*p) and (*d) prints two different answers( though this can also be explained if what i am thinking the cause in question 1).
Can somebody put some light on this, it will be really appreciated..and also if some one can explain the reasons behind this..
Many thanks
Answering your second question first:
The explanation is the fact that an int is generally 4 bytes, and the most significant bytes may be stored in the first two positions. A short, which is only 2 bytes, also stores its data in the first two positions. Clearly, then, storing 65536 in an int and a short, but pointing at the same memory location, will cause the data to be stored offset by two bytes for the int in relation to the short, with the two least significant bytes of the int corresponding to the storage for the short.
Therefore, when the compiler prints *d, it interprets this as a short and looks at the area corresponding to storage for a short, which is not where the compiler previously stored the 65536 when *p was written. Note that writing *p = 65536; overwrote the previous *d = 65536;, populating the two least significant bytes with 0.
Regarding the first question: The compiler does not store the 65536 for *p within 2 bytes. It simply goes outside the bounds of the memory you've allocated - which is likely to cause a bug at some point.
In C there is no protection at all for writing out of bounds of an allocation. Just don't do it, anything can happen. Here it seems to work for you because by some coincidence the space behind the two bytes you allocated isn't used for something else.
1) The granularity of the OS memory manager is 4K. An ovewrite by one bit is unlikely to trigger an AV/segfault, but will it corrupt any data in the adjacent location, leading to:
2) Undefined behaviour. This set of behaviour includes 'aparrently correct operation', (for now!).