Thread: Locating A Segmentation Fault

  1. #1

    Post Locating A Segmentation Fault

    Hello,

    Due to prominent request, I have written a short tutorial to assist programmers debug errors in this vast subject. Let's begin with a brief introduction.

    Introduction
    Having wondered about these errors and why they occur without pre-warning continuously lead programmers to ask questions like “Why do I get this error?” or “What is this error?”. These questions can be answered.

    The Truth Behind This Error
    This indecisive error can be difficult to pinpoint, and can take unnecessary debug-time to locate.

    Through this tutorial, we will explain what a segmentation fault is, how it is caused, and how it can be resolved. As previously stated, this error is indecisive and will take your know-how to detect it in your program.

    The following list is provided to greater your understanding of the segmentation fault error:

    • A segmentation fault can be an error in which a running program attempts to access memory not allocated to it and core dumps with a segmentation violation error.
    • A segmentation fault can be caused by memory misuse. Your program is attempting I/O on an area of memory it is not permitted to access. This can have many causes; some of the more common ones are "wild pointers" and buffer overflow (for example, allocating n characters for a buffer, and n+1 characters are written).
    • A segmentation fault (sometimes referred to as segfault for short) can be a particular error condition that can occur during the operation of computer software. In short, a segmentation fault occurs when a program attempts to access a memory location that it is not allowed to access, or attempts to access a memory location in a way it is not allowed to (e.g., attempts to write a read-only location).
    • A segmentation fault can be a type of error which occurs when you try to access a non-existent physical memory address.
    • A segmentation fault can occur if you freed memory and then within the scope of the same program try to re-use the same memory.
    • A segmentation fault, for software, can occur in case of hardware errors, for example the Hard Disc or Memory failure. To find out, try running memtest86 and/or any hard-disk diagnostic tools from the manufacturer.
    • A segmentation fault can be an error in which a running program attempts to access memory not allocated to it and core dumps with a segmentation violation error. This is often caused by improper usage of pointers in the source code, de-referencing a null pointer, or (in C) inadvertently using a non-pointer variable as a pointer.
    • A segmentation fault can occur when running a program that is reading or writing non-exist segment (physical memory space).
    • It can be a sporadic occurrence.

    A Closer Look
    With this information in mind, it may be easier to detect where a segmentation fault can occur. If we look at the following code, we can see that it looks a bit ambiguous. Does it fail when executed and display the Segmentation Fault message? It should, in most cases:

    Example 1.1
    Code:
    #include <string.h>
    
    int main() {
    	memset((char *)0x0, 42, 200);
    
    	return 0;
    }
    This is quite obvious as we try to fill the buffer 0x00. As we know 0x00 is 0 or NULL in the C/C++ language. This tells us we are requesting our program to write to memory that isn’t ours, that doesn’t exist, and that is simply nil. This is a perfect example of a Segmentation Fault. See Bulleted List #4 for greater detail.

    Next are some examples that cause segmentation faults or memory violations.

    Example 1.2
    Code:
    int main() {
    	char *abc;
    	abc[0] = 'z';
    
    	return 0;
    }
    This causes a violation because we are trying to modify abc, which at this point contains a non-valid address. Remember, abc is a pointer. Remember, a pointer is a variable containing the address of another variable. This program crashes because we are trying to write to memory that isn't ours. Like regular variables, un-initialized pointers will not cause a compiler error, but using an un-initialized pointer could result in unpredictable and potentially disastrous outcomes.

    In other cases, there are string literals and constants. Our following example will show that abc is a pointer that is initialized to contain the read-only address of a string constant; the pointer may subsequently be modified to point elsewhere, but the result is undefined if you attempt to modify the strings contents.

    Example 1.3
    Code:
    int main() {
    	char *abc = "Hello";
    
    	return 0;
    }
    This program, however, does not crash. It will only result in a crash if we try to change the contents of the string. This is similar to the const qualifier. The first rule of the const qualifier is this: A constant must be initialized, it is not possible to give it a value anywhere else. Keep in mind, the compiler does not give a warning if a pointer is unsafe/un-permitted to modify its contents.

    In our next example, you will see that trying to access or modify an array index that is out-of-bounds will also generate a segmentation fault.

    Example 1.4
    Code:
    int main() {
    	char abc[6] = "Hello";
    	abc[6] = '!';
    
    	return 0;
    }
    We know in C++ an array is a concrete data structure, which can be used to implement the Array or Vector data type (though other implementations are possible).

    C++ arrays have the following properties:
    • All elements in the array are of the same type
    • Elements are accessed by their index, starting at 0
    • The array has a fixed capacity, which must be known at compile time

    The fixed capacity of an array means that it cannot be increased or decreased once the array has been created.

    Array subscripts always start at zero in C, so the elements are abc[0], abc[1], …, abc[5]. Simply, counting 6 numbers starting and including 0 produces 5.

    Moving from simple examples, let’s view pointers to classes and pointers to structures. We know that until a pointer holds the address of a variable, it isn’t useful. Generally, pointers can be allocated using new/delete in C++, malloc() and free() in C, given the address of another object, or even take on a literal or a constant value/string. Some issues are that we create a pointer to a class and expect it to work. For structures/classes, the “.” operator connects the structure/class name and the member name. Pointers to structures/classes, on the other hand, use an alternative notation as a shorthand, using the operator “->”. Both of these operators read left to right. When dealing with pointers to structures/classes, the “->” operator will be used.

    Example 1.5
    Code:
    struct Foo {
    	int n;
    };
    
    int main() {
    	Foo *foo;
    	
    	foo->n = 4;
    
    	return 0;
    }
    A segmentation fault will occur when Example 1.4 is compiled and executed. The pointer foo to Foo contains no valid object or address, thus will result in a crash.

    Pointers, above all other variables, express computations better than others and are sometimes the only way. The flexibility of pointers can be dangerous. Memory is key when running a machine or a program. Learning how to handle memory in the C/C++ language is advantageous. This tutorial is a guide to exploring segmentation faults and why they occur. The best way to fix a segmentation fault is to learn how to handle memory, allocating and freeing, properly. There are many tutorials on how to allocate memory, pass object memory, and share memory in the other FAQ tutorials.

    Finding The Error
    On another note, detecting a segmentation fault can be difficult if you make it. A good tool is to look. Look for any pointers that may be un-initialized, modified as a literal or constant, de-referenced while a NULL value, or accessing memory that isn’t yours.

    Segmentation faults/violations are typically out-of-bounds array references and/or references through un-initialized or mangled pointers. Look very closely in your program for bizarre things like that. Common examples are:

    Example 2.1(a) [C Example]
    Code:
    #include <stdio.h>
    
    int main() {
    	int c;
    	scanf("%d", c);
    
    	return 0;
    }
    Example 2.1(b) [C++ Example]
    Code:
    #include <iostream>
    using namespace std;
    
    int main() {
    	int* p = new int[100];
    	cout << p[100];
    	delete []p;
    
    	return 0;
    }
    C Example: This isn’t good practice, and may crash because scanf()’s arguments must be pointers. If you want to store the result of a scanf() operation on a standard variable you should precede it with the reference operator, i.e. an ampersand sign (&).

    C++ Example: 100 spots were allocated. From 0 to 99. Modifying the 100'th index will cause a crash because it does not exist. It is an invalid subscript.

    Example 2.2(a) [C Example]
    Code:
    #include <stdio.h>
    
    int main() {
    	int c;
    	scanf("%d", &c);
    
    	return 0;
    }
    Example 2.2(b) [C++ Example]
    Code:
    #include <iostream>
    using namespace std;
    
    int main() {
    	int* p = new int[100];
    	cout << p[99];
    	delete []p;
    
    	return 0;
    }
    (Remember array subscripts in C and C++ start with 0)

    Conclusion
    There are a number of methods for finding out where the program went out of bounds. One method is to use printf(), cout, or any other means of printing, to print statements and determine how far the program runs before it crashes, and to print out the contents of interesting variables.

    On a last note, if you run into a “Segmentation Error” it usually means the same as a “Segmentation Fault” or “Segmentation Violation”; which all comes down to where it generally means that your program tried to access memory it shouldn't have, invariably as a result of stack corruption or improper pointer use.
    Segmentation Fault: I am an error in which a running program attempts to access memory not allocated to it and core dumps with a segmentation violation error. This is often caused by improper usage of pointers, attempts to access a non-existent or read-only physical memory address, re-use of memory if freed within the same scope, de-referencing a null pointer, or (in C) inadvertently using a non-pointer variable as a pointer.

  2. #2
    Registered User
    Join Date
    Apr 2004
    Posts
    210
    Quote Originally Posted by Stack Overflow
    There are a number of methods for finding out where the program went out of bounds. One method is to use printf(), cout, or any other means of printing, to print statements and determine how far the program runs before it crashes, and to print out the contents of interesting variables.
    I hope you don't mind replies to this topic.

    Another option to find memory leaks and locate invalid memory access is the use of tools like Valgrind. Valgrind has an addresscheck tool that allows you to track access to invalid memory locations, even those that do not neccessarly lead to a segmentation fault.
    Maybe some other people could list similar windows tools, I don't have any experience there :/
    main() { int O[!0<<~-!0]; (!0<<!0)[O]+= ~0 +~(!0|!0<<!0); printf("a function calling "); }

  3. #3
    Hi,

    I don't mind at all. All constructive feedback is welcomed.

    Thanks for the information about the tool, Valgrind. I've never heard of it before. I'll install it on my Red Hat system and give it a go.


    - Stack Overflow
    Segmentation Fault: I am an error in which a running program attempts to access memory not allocated to it and core dumps with a segmentation violation error. This is often caused by improper usage of pointers, attempts to access a non-existent or read-only physical memory address, re-use of memory if freed within the same scope, de-referencing a null pointer, or (in C) inadvertently using a non-pointer variable as a pointer.

  4. #4
    I like code Rouss's Avatar
    Join Date
    Apr 2004
    Posts
    131
    One way I find segfaults (damn them!) is to use the gdb debugger.
    I use gcc as a compiler, so it may be different on other compilers. Compile your program with the -g option, the run the command gdb yourprog.
    example
    Code:
    gcc -o myprog program.c -g
    gdb myprog
    In gdb, type the command run... It should tell you that your program had a segfault, and maybe what line it is around.
    then typing bt (backtrace) will show you the last things your program did or tried to do... with any good line numbers.
    That should give you a good lead on where to start looking for mistakes.

    EDIT:
    here is an example on using gdb based on some of SO's source.
    Code:
    [ryan]$ cat segfault.c
    #include <stdio.h>
    
    int main(void)
    {
        int num;
        printf("Enter a number: ");
        scanf("%d", num);
    
        return 0;
    }
    
    [ryan]$ gcc -o segfault segfault.c -g
    [ryan]$ ./segfault
    f
    [ryan]$ ./segfault
    4
    Segmentation fault
    [ryan]$ gdb ./segfault
    GNU gdb 6.1-debian
    Copyright 2004 Free Software Foundation, Inc.
    GDB is free software, covered by the GNU General Public License, and you are
    welcome to change it and/or distribute copies of it under certain conditions.
    [ryan]$ gcc -o segfault segfault.c -g
    [ryan]$ ./segfault
    Enter a number: 5
    Segmentation fault
    [ryan]$ gdb ./segfault
    GNU gdb 6.1-debian
    Copyright 2004 Free Software Foundation, Inc.
    GDB is free software, covered by the GNU General Public License, and you are
    welcome to change it and/or distribute copies of it under certain conditions.
    Type "show copying" to see the conditions.
    There is absolutely no warranty for GDB.  Type "show warranty" for details.
    This GDB was configured as "i386-linux"...Using host libthread_db library "/lib/tls/libthread_db.so.1".
    
    (gdb) run
    Starting program: /home/ryan/Code/C/segfault
    Enter a number: 5
    
    Program received signal SIGSEGV, Segmentation fault.
    0xb7ef672b in _IO_vfscanf () from /lib/tls/libc.so.6
    (gdb) bt
    #0  0xb7ef672b in _IO_vfscanf () from /lib/tls/libc.so.6
    #1  0xb7f00c68 in scanf () from /lib/tls/libc.so.6
    #2  0xb7fd0d20 in _IO_file_jumps () from /lib/tls/libc.so.6
    #3  0x08048525 in _IO_stdin_used ()
    #4  0xbffffa74 in ?? ()
    #5  0x00000000 in ?? ()
    #6  0xb7fd7fcc in ?? () from /lib/tls/libc.so.6
    #7  0x080483f3 in main () at segfault.c:7
    (gdb) quit
    The program is running.  Exit anyway? (y or n) y
    [ryan]$
    So you can see that the segfault is on line 7.
    Hope this helps some.
    Last edited by Rouss; 12-13-2004 at 09:45 PM.

  5. #5
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    I think the main purpose of the OP was to explain how without the help of anything other than your C compiler, you can locate your own segfaults. Not everyone has a debugger or something like electric fence to hunt them down for them. However, by sprinkling printf statements through your code, you can usually hunt them down yourself without too much trouble.

    One thing you might want to add however, is that you may want to be sure and flush the output stream to be sure what you're printing does in fact show up.

    Quzah.
    Hope is the first step on the road to disappointment.

  6. #6
    ---
    Join Date
    May 2004
    Posts
    1,379
    But of course debugger's are also useful when you're not getting the right output, not necessarily a seg fault. But I guess thats kinda off topic.

  7. #7
    Banned master5001's Avatar
    Join Date
    Aug 2001
    Location
    Visalia, CA, USA
    Posts
    3,685
    It seems to me the longer you program the more in tune you get with which line of code you made a little mistake. I'd say more than 75% of the time when I get a seg fault I know exactly what it was that broke.

    >However, by sprinkling printf statements through your code, you can usually hunt them down yourself without too much trouble

    Maybe I just think debuggers are cheating, but more often than not I'll do the prinf technique. Though, printf can also cause seg faults too
    Last edited by master5001; 12-14-2004 at 07:51 AM.

  8. #8
    Hello,

    I thank everyone for their comments on Segmentation Faults. My short tutorial was to express the error, and how it's caused in great detail.

    For those of you that do have a debugger, use it. It may save you time by using gdb, Valgrind, or any other debugger you may have.

    My intention was to help those that don't have access to a debugger. A lot of new-comers get frustrated when they can't resolve a segmentation fault, and I'm hoping this guide can help them through it.

    If they happen upon a debugger, I'm sure Rouss's post can help them use gdb if they have it, and/or Nyda's post if they are looking for an open-source tool.

    Of course Quzah has a valid point. Flush the output stream if using printf() before the segmentation fault occurs, so it shows up.


    - Stack Overflow
    Segmentation Fault: I am an error in which a running program attempts to access memory not allocated to it and core dumps with a segmentation violation error. This is often caused by improper usage of pointers, attempts to access a non-existent or read-only physical memory address, re-use of memory if freed within the same scope, de-referencing a null pointer, or (in C) inadvertently using a non-pointer variable as a pointer.

  9. #9
    & the hat of GPL slaying Thantos's Avatar
    Join Date
    Sep 2001
    Posts
    5,681
    Another tip
    Create an input file and then redirect input to that file.
    Example lets say the program asks your name age and gender. Then the input file may look like:
    Code:
    Thantos
    24
    male
    To redirect standard input use the < character as such:
    Code:
    program-name < file-name
    example:
    Code:
    ./hello < world.txt
    This helps you in a few ways:
    1) You have a set input which means you should get a set output
    2) Time: It can read from the file faster then you can type
    3) Allows you to focus on the soley on the output

    Print all error messages to stderr (standard error) and not stdout (standard output):
    This allows you to seperate the error messages from the normal program dialog using command line redirection.
    You can print to the stderr using fprintf()
    Code:
    fprintf(stderr, "Seg Fault Test Location #%d\n", X);
    To redirect stdout you can use the > character.
    Code:
    ./hello > world.txt
    now the output of hello will be written to world.txt
    The same can be done for stderr using the >& characters.

    How does this help you?
    Well if you program has a lot of user prompting and dialog then it can be harder to notice your error messages. So in conjunction with an input file redirecting stdin and stdout allows you to just view the errors.

    Use a macro to save yourself some typeing:
    One macro I use a lot when trying to locate a seg fault is the following:
    Code:
    #define SEG(X) fprintf(stderr, "Seg Fault Test Location #%d\n", X)
    Then I'll liberally apply them throughout my code (I generally only do one function at a time so I don't have so much cleanup)
    Code:
    int main(void)
    {
      int x, y, z;
      SEG(1);
      x = 2;
      SEG(2);
      y = 3;
      SEG(3);
      z = 4;
      SEG(4);
      printf("%d %d %d\n", x, y, z);
      SEG(5);
      return 0;
    }
    Since I have my input and output seperated I can just see where my test prints stop (or if they all go through I know I need to move to a different area).

    For the macro to really be the most effective you need to do all three parts (make an input file, put all error messages to stderr, redirect stdin and stdout).

  10. #10
    I like code Rouss's Avatar
    Join Date
    Apr 2004
    Posts
    131
    Sorry if my comment on gdb was off topic. Sometimes it is more helpful to use though, like in my class on ADTs this semester. Every program was 500-600 lines about linked lists, stacks, queues, trees, and what not. Lots of pointers. Some segfaults were hard to find. And I didn't start using gdb until the last assignment.

    If you don't have access to gdb or any of the tools listed in here, a macro I used (and still use for other purposes) is
    Code:
    #define DEBUG if(1)
    
    // used like
    DEBUG puts("This location");
    // or can be used with blocks
    DEBUG {
      puts("You can put multiple statements here.");
      puts("see!");
    }
    Then you can turn the statements off by changing the 1 to a 0 in the #define, that way you don't have to delete them until you are sure you are done with them.

  11. #11
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,005
    The "print some information" comments remind me to mention assert.
    7. It is easier to write an incorrect program than understand a correct one.
    40. There are two ways to write error-free programs; only the third one works.*

  12. #12
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,660
    Beware - http://www.houghi.org/jargon/heisenbug.php
    Trying to examine the problem changes the problem.

  13. #13
    & the hat of GPL slaying Thantos's Avatar
    Join Date
    Sep 2001
    Posts
    5,681
    Oh yes I've meant with that bug before. It was real fun trying to figure it out

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Why am I getting segmentation fault on this?
    By arya6000 in forum C++ Programming
    Replies: 6
    Last Post: 10-12-2008, 06:32 AM
  2. segmentation fault... first time with unix...
    By theMethod in forum C Programming
    Replies: 16
    Last Post: 09-30-2008, 02:01 AM
  3. Segmentation fault
    By bennyandthejets in forum C++ Programming
    Replies: 7
    Last Post: 09-07-2005, 05:04 PM
  4. Segmentation fault
    By NoUse in forum C Programming
    Replies: 4
    Last Post: 03-26-2005, 03:29 PM
  5. Segmentation fault...
    By alvifarooq in forum C++ Programming
    Replies: 14
    Last Post: 09-26-2004, 12:53 PM