Why my dangling pointer doesn't cause a segmentation fault? - c

My code:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *p = (int *)malloc(sizeof(int));
free(p);
*p = 42;
return 0;
}
I created a pointer, then I pointed it to allocated space and finally I had assigned 42 to it.
In my opinion it should not work, it should cause a segmentation fault, but it works.
So, why?
PS: I normally compiled it with Gcc on Linux

Pure luck. The behavior in this case is undefined. I.e.: no expectations can be made as to what may happen.

In my opinion it should not work [...] but it works.
Don't worry, it doesn't work.
it should cause a segmentation fault
Tell that to the C standards committee. It's just undefined behavior, it isn't required to crash.

The more elaborate answer beyond "undefined" is that you can write to arbitrary memory locations in C as long as you stay within the processes allocated memory areas. Depending on OS, overwriting code may be allowed or not. The ill effects only turn up, once some other code of your process gets confused by what is found at the garbled memory location. Since your program exits right away after messing up the memory, the chance for some of its code to get confused is obviously small.

The behavior in this case is undefined ,
it is a possibility with undefin behavior

you display the memory address of p before and after free to check "p" with :
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *p = (int *)malloc(sizeof(int));
printf("before \n %p \n",p);
free(p);
*p = 42;
printf("after\n %p \n",p);
printf(" %d \n",*p);
return 0;
}
before and after free we have the same address memory because free() don't assign NULL to p pointer, so *p = 42; work like static assignment although it's undefined behaviour.
suggest to use the FREE macro :
#define FREE(X) \
free(X);\
X=NULL;
test with this macro and you will see the expected behaviour

Related

the function of malloc(using malloc correctly)

so I'm quite new in this, sorry if it sound like a dumb question
I'm trying to understand malloc, and create a very simple program which will print "ABC" using ASCII code
here is my code (what our professor taught us) so far
char *i;
i = malloc(sizeof(char)*4);
*i = 65;
*(i+1) = 66;
*(i+2) = 67;
*(i+3) = '\0';
what I don't understand is, why do I have to put malloc there?
the professor told us the program won't run without the malloc,
but when I tried and run it without the malloc, the program run just fine.
so what's the function of malloc there?
am I even using it right?
any help and or explanation would be really appreciated
the professor told us the program won't run without the malloc
This is not quite true, the correct wording would be: "The program's behavior is undefined without malloc()".
The reason for this is that
char *i;
just declares a pointer to a char, but there's no initialization -- this pointer points to some indeterminate location. You could be just lucky in that writing values to this "random" location works and won't result in a crash. I'd personally call it unlucky because this hides a bug in your program. undefined behavior just means anything can happen, including a "correct" program execution.
malloc() will dynamically request some usable memory and return a pointer to that memory, so after the malloc(), you know i points to 4 bytes of memory you can use. If malloc() fails for some reason (no more memory available), it returns NULL -- your program should test for it before writing to *i.
All that said, of course the program CAN work without malloc(). You could just write
char i[4];
and i would be a local variable with room for 4 characters.
Final side note: sizeof(char) is defined to be 1, so you can just write i = malloc(4);.
Unfortunately, "runs fine" criterion proves nothing about a C program. Great deal of C programs that run to completion have undefined behavior, which does not happen to manifest itself on your particular platform.
You need special tools to see this error. For example, you can run your code through valgrind, and see it access uninitialized pointer.
As for the malloc, you do not have to use dynamic buffer in your code. It would be perfectly fine to allocate the buffer in automatic memory, like this:
char buf[4], *i = buf;
You have to allocate space for memory. In the example below, I did not allocate for memory for i, which resulted in a segmentation fault (you are trying to access memory that you don't have access to)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *i;
strcpy(i, "hello");
printf("%s\n", i);
return (0);
}
Output: Segmentation fault (core dumped)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *i;
/*Allocated 6 spots with sizeof char +1 for \0 character*/
i = malloc(sizeof(char) * 6);
strcpy(i, "hello");
printf("%s\n", i);
return (0);
}
Result: hello
Malloc allows you to create space, so you can write to a spot in memory. In the first example, "It won't work without malloc" because i is pointing to a spot in memory that doesn't have space allocated yet.

Is this an undefined behaviour?

So I just wanted to ask is this an undefined behavior when the commented line is added. Although there is no compilation errors and both of them give the same answers. I would like to know is there any difference. Is the address being overwritten by the address of a. Also If one were to do this (i.e allocate memory for b), would memcpy() be a good solution. This may be a trivial example but I would like to understand the difference.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *a;
int *b;
a=malloc(sizeof(int));
//b=malloc(sizeof(int));
int c=6;
a=&c;
b=a;
printf("%d\n",*b);
return 0;
}
When you uncomment //b=malloc(sizeof(int)); part, you'll end up creating memory leak, as later, you'll be losing the pointer returned by malloc() and will have no way to free() it.
FWIW, you already have the issue with a, as you overwrite malloc()ed memory by the address of c.
It is not UB, though, a bad practice, anyway.
For the above code, you can remove both the malloc()s, safely. You don't need them.
That said, int main() should be int main(void), at least, to conform to the standards.
b=malloc(sizeof(int));
int c=6;
a=&c;
b=a;
Since the value of b is changed before it's used, that you assign the return value of malloc to b makes no difference. However, you don't free it, so you do leak the memory allocated.
No UB.
I don't think this code cause undefined behavior, but this code do cause memory leak.
Don't use malloc() if you don't need additional buffer.

Is malloc needed for this int pointer example?

The following application works with both the commented out malloced int and when just using an int pointer to point to the local int 'a.' My question is if this is safe to do without malloc because I would think that int 'a' goes out of scope when function 'doit' returns, leaving int *p pointing at nothing. Is the program not seg faulting due to its simplicity or is this perfectly ok?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct ht {
void *data;
} ht_t;
ht_t * the_t;
void doit(int v)
{
int a = v;
//int *p = (int *) malloc (sizeof(int));
//*p = a;
int *p = &a;
the_t->data = (void *)p;
}
int main (int argc, char *argv[])
{
the_t = (ht_t *) malloc (sizeof(ht_t));
doit(8);
printf("%d\n", *(int*)the_t->data);
doit(4);
printf("%d\n", *(int*)the_t->data);
}
Yes, dereferencing a pointer to a local stack variable after the function is no longer in scope is undefined behavior. You just happen to be unlucky enough that the memory hasn't been overwritten, released back to the OS or turned into a function pointer to a demons-in-nose factory before you try to access it again.
Not every UB (undefined behaviour) results in a segfault.
Normally, the stack's memory won't be released back to the OS (but it might!) so that accessing that memory works. But at the next (bigger) function call, the memory where the pointer points to might be overwritten, so your data you felt like bing safe there is lost.
malloc() inside a function call will work because it stores on heap.
The pointer remains until you free the memory.
And yes, not every undefined behaviour will result in segmentation fault.
It does not matter that p does not point at anything on return from doit.
Because, you know, p isn't there any more either.
It does matter that you are reading the pointer to a no-longer-existing object in main though. That's UB, but harmless on most modern platforms.
Even worse though, you are reading the non-existent object it once pointed to, which is straight Undefined Behavior.
Still, nobody is obliged to catch you:
Can a local variable's memory be accessed outside its scope?
As an aside, Don't cast the result of malloc (and friends).
Also, be aware that not free-ing memory is not harmless on all platforms: Can I avoid releasing allocated memory in C with modern OSes?
Yes, the malloc is needed, otherwise the pointer would point on the 4-byte space of the stack, which would be used by other data, if you called other functions or created now local variables.
You can see that if you call that function afterwards with a value of 10:
void use_memory(int i)
{
int f[128]={};
if(i>0)
{
use_memory(i-1);
}
}

Use memory on stack

What are the possible behaviors of the program below?
I have tried to allocate and use memory on stack,
and print the memory block pointed by p, output are characters of '\0'.
I known technically it is not available when the function returns.
However, why not the program crash, or print some random garbage?
#include <cstring>
#include <cstdio>
#include <cstdlib> //malloc
char* getStackMemory(){
char mem[10];
char* p = mem;
return p;
}
int main(){
char* p = getStackMemory();
strcpy(p, "Hello!");
printf("%s\n", p);
for(int i = 0; i<10; i++){
printf("%c\n", p[i]);
}
return 0;
}
As per you already know that memory of char mem[10]; on stack and it is not available when the function returns. So i only says that it will cause you Undefined Behavior.
why not the program crash, or print some random garbage?
The program will not crash as you are not accessing any illegal memory. The stack memory is a part of your program and as long as you are accessing the memory in a valid range the program will not crash. Yes, you can modify the stack memory whether the function is in that stack frame or not.
Now accessing the memory which is not in the current stack frame will lead to an Undefined Behavior. This is compiler dependent. Most of the compiler will print the garbage value. I don't know which compiler you are using!!
I would say try to understand the basic concept of stack memory in C/C++ programs. An I would suggest also look into heap memory.
It is because after the function returns, the stack is unavailable however u r returning the address of that location from that function which is getting stored in pointer p, so the program does not crash but gives garbage value.
Here, the program will not crash rather it will print some garbage value. When it will return stack will not be available and hence will give garbage value.

Behavior of bad pointers at runtime

I've been doing some tests with pointers and came across the two following scenario. Can anybody explain to me what's happening?
void t ();
void wrong_t ();
void t () {
int i;
for (i=0;i<1;i++) {
int *p;
int a = 54;
p = &a;
printf("%d\n", *p);
}
}
void wrong_t() {
int i;
for (i=0;i<1;i++) {
int *p;
*p = 54;
printf("%d\n", *p);
}
}
Consider these two versions of main:
int main () {
t();
wrong_t();
}
prints:
54\n54\n, as expected
int main () {
wrong_t();
}
yields:
Segmentation fault: 11
I think that the issue arises from the fact that "int *p" in "wrong_t()" is a "bad pointer" as it's not correctly initialized (cfr.: cslibrary.stanford.edu/102/PointersAndMemory.pdf, page 8). But I don't understand why such problem arises just in some cases (e.g.: it does not happen if I call t() before wrong_t() or if I remove the for loop around the code in wrong_t()).
Because dereferencing an uninitialised pointer (as you correctly guessed) invokes undefined behaviour. Anything could happen.
If you want to understand the precise behaviour you're observing, then the only way is to look at the assembler code that your compiler produced. But this is normally not very productive.
What happens is almost certainly:
In both t and wrong_t, the definition int *p allocates space for p on the stack. When you call only wrong_t, this space contains data left over from previous activity (e.g., from the code that sets up the environment before main is called). It happens to be some value that is not valid as a pointer, so using it to access memory causes a segment fault.
When you call t, t initializes this space for p to contain a pointer to a. When you call wrong_t after this, wrong_t fails to initialize the space for p, but it already contains the pointer to a from when t executed, so using it to access memory results in accessing a.
This is obviously not behavior you may rely on. You may find that compiling with optimization turned on (e.g., -O3 with GCC) alters the behavior.
In wrong_t function, this statement *p = 54; is interesting. You are trying to store a value into a pointer p for which you haven't yet allocated the memory and hence, the error.

Resources