Go4Expert

Go4Expert (http://www.go4expert.com/)
-   C (http://www.go4expert.com/articles/c-tutorials/)
-   -   Reasons For Segmentation Fault In C (http://www.go4expert.com/articles/reasons-segmentation-fault-c-t27220/)

poornaMoksha 27Nov2011 07:24

Reasons For Segmentation Fault In C
 
There are times when you write a small or a big code and when you execute it you get a very small and precise output 'Segmentation fault'. In a small piece of code its still easy to debug the reason for this but as the code size grows it becomes very difficult to debug. Here in this article, I am providing some example scenarios which will demonstrate some reasons because of which a segmentation fault can occur.

Meaning of Segmentation Fault



Before jumping on to the actual scenarios, lets quickly discuss what does Segmentation Fault means?

A segmentation fault occurs mainly when our code tries to access some memory location which it is not suppose to access.

For example :
  1. Working on a dangling pointer.
  2. Writing past the allocated area on heap.
  3. Operating on an array without boundary checks.
  4. Freeing a memory twice.
  5. Working on Returned address of a local variable
  6. Running out of memory(stack or heap)

Examples of Segmentation Fault in C



1) Working on a dangling pointer.

Well, before discussing this scenario of segmentation fault, lets understand what is dangling pointers. A pointer which holds memory address of a memory which is already freed is known as a dangling pointer. You cannot figure out whether a given pointer is dangling or not until you use it. When a dangling pointer is used, usually a segmentation fault is observed.

Now, lets look at a code to understand it :

Code:

#include<stdio.h>
 #include<stdlib.h>
 
 int main(void)
 {
    char *p = malloc(3);
 
    *p = 'a';
    *(p+1) = 'b';
    *(p+2) = 'c';
 
    free(p);
 
    *p = 'a';
 
    return 0;
 }

In the code above, we have malloc'd 3 bytes on heap and stored the address of first byte in a pointer 'p'. Next we initialized these three bytes. Next we freed this memory and after that we are trying to use this memory again. Well this is not permitted as once a memory is freed, it no longer belongs to our process. Though, if you run the above code, it may not give a segmentation fault immediately as free() returns the memory to heap and now its up to the implementation of heap to take it back to its pool. Once its taken back to heap by kernel then the code above will start giving segmentation faults.


Lets take another example :

Code:

#include<stdio.h>
 #include<stdlib.h>
 #include<string.h>
 
 int main(void)
 {
    char *p ;
 
    strcat(p, "abc");
    printf("\n %s \n", p);
 
    return 0;
 }

In the code above, we have pointer 'p', to which we have not allocated any memory. Now we use the garbage address held by the pointer 'p' in the function 'strcat()'. So in the implementation of strcat(), whenever 'p' is accessed, it will give a segmentation fault.

A yet another example could be :

Code:

#include<stdio.h>
 #include<stdlib.h>
 #include<string.h>
 
 
 void func(char ** argv)
 {
    char arr[2];
    strcpy(arr, argv[1]);
 
    return;
 }
 
 int main(int argc, char *argv[])
 {
    func(argv);
    return 0;
 }

In the above code, we try to access the second argument from command line in the function func() without even checking whether the user has even provided the second argument or not. If the user did not provide then argv[1] will point to a location that our code does not have access to. Hence, in that case we will definitely get a segmentation fault.

2)Writing past the allocated area on heap.

There are times when a logic inadvertently writes past the allocated area on heap. This may happen while performing some operations in a loop or not doing array bound checks etc. So this type of situation also results in a segmentation fault. For example, look at the following code :

Code:

#include<stdio.h>
 #include<stdlib.h>
 
 int main(void)
 {
    char *p = malloc(3);
 
    int i = 0;
 
    for(i=0;i<0Xffffffff;i++)
    {
        p[i] = 'a';
    }
 
    printf("\n %s \n", p);
 
    return 0;
 }

In the example above, we allocate some bytes to pointer 'p' but try to write way past these bytes in a loop. So, the result we get is a segmentation fault.

3) Operating on an array without boundary checks.

In this scenario, the logic is flawed in a way that an array is written out of its boundary limits and in a rare scenario (or in case of exploits), this buffer overflow may result in overwriting the return address(ie the address to return after executing the present function). And hence returning on a garbage address and executing the instruction kept there may very well cause segmentation fault.

Lets look the following code :

Code:

#include<stdio.h>
 #include<stdlib.h>
 #include<string.h>
 
 
 void func(char ** argv)
 {
    char arr[2];
    strcpy(arr, argv[1]);
 
    return;
 }
 
 int main(int argc, char *argv[])
 {
    func(argv);
    return 0;
 }

In the code above, we are passing the command line argument array to function func(). Inside the function func(), we try to copy the second command line argument (with index '1') into the array arr. The problem here is the function we use to copy. We use strcpy() which has no concern with the capacity of array arr. This function will not detect or prevent a buffer overflow. So if we try to enter very huge string through this logic presented above, we will definitely overwrite the return address kept in the stack of this function and will cause a segmentation fault to happen.

Here is the output of the code above(I tried to run it twice with different command line args) :

Code:

~/practice $ ./segfault abc
  ~/practice $

Code:

~/practice $ ./segfault abcjflcnmscn,snlkewfdebddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
 Segmentation fault

As can be clearly seen, in the first attempt, the code worked fine but in the second attempt, a large command line argument probably overwrote the return address stored on stack of the function func() and hence when the control went back to this overwritten value any damn thing could have caused a segmentation fault as this memory location mostly(until you are very lucky) does not belong to our process.

4) Freeing a memory twice.

This is a bit specific to function free() but is a very common reason for segmentation faults to occur. The specification of free() specifies that if this function is used again on an already freed pointer, the results are undefined and mostly we see a segmentation fault in this scenario.

Lets quickly see the code :

Code:

#include<stdio.h>
 #include<stdlib.h>
 #include<string.h>
 
 int main(int argc, char *argv[])
 {
    char *p = malloc(8);
 
 
    free(p);
    free(p);
    return 0;
 }

As clearly seen in the code above, we have allocated memory once but we have freed it back to back twice. This is wrong practice and should be avoided.

5) Working on Returned address of a local variable

I this scenario, the address of a local variable is returned to calling function and this address is used there. For example, consider the following code :

Code:

#include<stdio.h>
 #include<stdlib.h>
 #include<string.h>
 
 
 char* func()
 {
    char c = 'a';
    return &c;
 }
 
 int main(int argc, char *argv[])
 {
    char *ptr = func();
    char arr[10];
    memset(arr,'0', sizeof(arr));
    arr[0] = *ptr;
    return 0;
 }

In the code above, we did exactly the same now since we all know that the stack of the function is unwind-ed when func() returns. So, its fatal to use any address out of a function stack that has already been unwind-ed. This may cause a segmentation fault.

6) Running out of memory.

It may happen that we run out of memory. This memory can be a stack memory or a heap memory. Lets consider the following two examples to understand this :

Code:

#include<stdio.h>
 #include<stdlib.h>
 #include<string.h>
 
 int main()
 {
    main();
 }

If you execute the code above, it continuously calls on main() recursively. So with every call, a stack is formed and none of these stacks is ever unwind-ed as we never stop calling main. So at a point all of the process's stack memory gets eaten up and then we get segmentation fault.

Consider example of heap memory :

Code:

#include<stdio.h>
 #include<stdlib.h>
 #include<string.h>
 
 
 int main()
 {
    unsigned int i = 0;
 
    for(i=0; i< 0xFFFFFFFF;i++);
        char *p = malloc(100);
 
    return 0;
 }

The code above may cause you program to segment fault once all the heap memory is consumed.

Conclusion



To conclude, in this article we studied the different ways in which one could screw up his/her program and get segmentation fault. This article should act as a good resource for those who are getting this error but not able to understand the reason.

Stay tuned for more!!!

lionaneesh 27Nov2011 14:47

Re: Reasons For Segmentation Fault In C
 
Nice article! :)

poornaMoksha 27Nov2011 16:21

Re: Reasons For Segmentation Fault In C
 
Thanks

prestito inpdap 29Nov2011 14:50

Re: Reasons For Segmentation Fault In C
 
The information is very interesting, I have been very useful for my work and my personal interests. Thank you.
By the way, I'm new to this forum, glad to be here!

poornaMoksha 29Nov2011 14:57

Re: Reasons For Segmentation Fault In C
 
Quote:

Originally Posted by prestito inpdap (Post 89652)
The information is very interesting, I have been very useful for my work and my personal interests. Thank you.
By the way, I'm new to this forum, glad to be here!

Thank you!!! Welcome to G4E. :happy:

manjuchandra 29Nov2011 15:14

Re: Reasons For Segmentation Fault In C
 
really thanks to share this information.

poornaMoksha 29Nov2011 15:18

Re: Reasons For Segmentation Fault In C
 
Quote:

Originally Posted by manjuchandra (Post 89655)
really thanks to share this information.

You are welcome buddy!!! :happy:

ashu44 13Dec2011 11:27

Re: Reasons For Segmentation Fault In C
 
very useful information thanx poornaMoksha to share it Please post some other useful information .

poornaMoksha 13Dec2011 11:30

Re: Reasons For Segmentation Fault In C
 
Quote:

Originally Posted by ashu44 (Post 90174)
very useful information thanx poornaMoksha to share it Please post some other useful information .

Sure. I'll be back with more articles from 21st of December. Stay tuned!!!


All times are GMT +5.5. The time now is 06:12.