75

NOTE: We have a lot of segfault questions, with largely the same answers, so I'm trying to collapse them into a canonical question like we have for undefined reference.

Although we have a question covering what a segmentation fault is, it covers the what, but doesn't list many reasons. The top answer says "there are many reasons", and only lists one, and most of the other answers don't list any reasons.

All in all, I believe we need a well-organized community wiki on this topic, which lists all the common causes (and then some) to get segfaults. The purpose is to aid in debugging, as mentioned in the answer's disclaimer.

I know what a segmentation fault is, but it can be hard to spot in the code without knowing what they often look like. Although there are, no doubt, far too many to list exhaustively, what are the most common causes of segmentation faults in C and C++?

ikegami
  • 367,544
  • 15
  • 269
  • 518
CodeMouse92
  • 6,840
  • 14
  • 73
  • 130
  • 1
    I dont think the old answer is hard to find, actually I just recently found it (easily) while searching the web for seg fault – 463035818_is_not_an_ai Oct 09 '15 at 21:34
  • Even if it's easy to find, it was closed (not sure why, given the undefined reference question was the same style), so it cannot be maintained very easily. It took me about two hours to find it, and I was looking for it or anything like it. – CodeMouse92 Oct 09 '15 at 21:35
  • 2
    http://stackoverflow.com/q/2346806/212870 isn't closed. – Alan Stokes Oct 09 '15 at 21:41
  • No, and I linked to it. My reasoning here is building a canonical WHY, not a canonical WHAT. Apparently that other question isn't canonical enough to serve as a duplicate, as it often isn't. We have way too many identical segfault Qs all asking WHY. My reasoning might or might not be flawed, but...*shrug*, I suppose time will tell. – CodeMouse92 Oct 09 '15 at 21:44
  • 5
    The problem with this is it will re-enforce the myth that the below "causes" will lead to a segmentation fault. We'd be much better off educating about UB more generally. – Lightness Races in Orbit Oct 09 '15 at 22:39
  • I'll rephrase the answer to account for that. I still think we need this to a) serve as an obvious central question for marking other duplicates, and b) aid in diagnosing a segfault. – CodeMouse92 Oct 09 '15 at 22:41
  • No.1 reason for posts re segfaults is no debugging done. – Martin James Oct 09 '15 at 23:52
  • 1
    I have to agree with @LightnessRacesinOrbit as I say in my answer [here](http://stackoverflow.com/a/18986406/1708801) *A segmentation fault is an implementation defined behavior the standard does not define how the implementation should deal with undefined behavior*. In order for this to make any sense you have to talk about specific platforms and specific compiler versions and even then you are thin ice. – Shafik Yaghmour Oct 10 '15 at 00:20
  • 2
    That being said, "it's UB" is over-invoked: as long as a platform and OS is specified, sometimes it's worth examining the practical consequences of our actions. e.g. "got segfault? check for null pointer dereference first and foremost". Some are almost certs, like that one; others are just high probability. In that sense, this could function fairly well as a debugging guide ... as long as it has sufficient disclaimers and explains the situation _very_ carefully! FWIW, on the whole this Q&A is very good. – Lightness Races in Orbit Oct 10 '15 at 00:21
  • The C standard has an almost 20 page long appendix that lists things that **might** cause undefined behavior. That standard also has a disclaimer that this list is not definitive. Even worse, some things listed as UB in the C standard are very well defined behavior on some systems (e.g., various conflicts between POSIX and the C standard). The C++ standard? It doesn't even try to list all the things that can cause UB. Asking for a definitive list of things that can cause segfaults is akin to asking to solving the halting problem. – David Hammen Oct 10 '15 at 00:22
  • @ShafikYaghmour, I added that link to the disclaimer. Fantastically written answer! – CodeMouse92 Oct 10 '15 at 00:23
  • @DavidHammen, unfortunately, standards are typically impenetrable to beginner and some intermediate level programmers. I notice that most segfaults are caused by the same few things. Thus, this isn't meant to be scholastically exhaustive as much as an organized list of the most common causes. I reworded the question to clarify that. – CodeMouse92 Oct 10 '15 at 00:42
  • I think it can be fit in briefly with a link towards the bottom of the answer, though adding more than that would rather defeat the purpose of "common" causes, I would think. – CodeMouse92 Oct 10 '15 at 02:32
  • you should highlight more relationship between segfault and undefined behaviour. @LightnessRacesinOrbit: I had similar idea once to create question listing common UB in C, but on a related question on SO, I found out that that type of question is not welcome – Giorgi Moniava Oct 15 '15 at 18:26
  • @Giorgi, I've tried. It's a community wiki, so you're welcome to clarify it further. Be sure to read the disclaimer of intent first, of course! – CodeMouse92 Oct 15 '15 at 18:28
  • @CodeMouse92 This is a good article for a documentation topic. Can you add it. If not, I can also add it with a reference here. – Rishikesh Raje Mar 09 '17 at 08:59
  • This question is too broad. Such topics now have a place on https://stackoverflow.com/documentation. This should be closed. Such topics already exist on documentation, and if they don't this post should be moved there. – 2501 Mar 09 '17 at 09:09
  • @2501, be aware, this existed before Documentation, and is a common duplicate close target. I agree this may have a place on Documentation, but I don't agree this is worth closing - it's already a community wiki. – CodeMouse92 Mar 09 '17 at 22:04
  • @CodeMouse92 I'm was aware of both. This should not be a duplicate target for closure (remember that duplicate closure must be an exact duplicate), as the question itself is too broad (let's be honest, we both know that), and should be closed. Answers that may contain the answer to the error, but don't explain which part of the answer is the solution are not a solution. – 2501 Mar 10 '17 at 07:32
  • It seems your intent of the question is: *well-organized community wiki*. StackOverflow is not that. Documentation is. And now, it exist. I strongly suggest you move the entire post to documentation and get reputation there. Use mod flags if you need help deleting this post. – 2501 Mar 10 '17 at 07:35
  • I don't agree with your assessment. If the community consensus is to close, I shall close. – CodeMouse92 Mar 11 '17 at 00:01

1 Answers1

87

WARNING!

The following are potential reasons for a segmentation fault. It is virtually impossible to list all reasons. The purpose of this list is to help diagnose an existing segfault.

The relationship between segmentation faults and undefined behavior cannot be stressed enough! All of the below situations that can create a segmentation fault are technically undefined behavior. That means that they can do anything, not just segfault -- as someone once said on USENET, "it is legal for the compiler to make demons fly out of your nose.". Don't count on a segfault happening whenever you have undefined behavior. You should learn which undefined behaviors exist in C and/or C++, and avoid writing code that has them!

More information on Undefined Behavior:


What Is a Segfault?

In short, a segmentation fault is caused when the code attempts to access memory that it doesn't have permission to access. Every program is given a piece of memory (RAM) to work with, and for security reasons, it is only allowed to access memory in that chunk.

For a more thorough technical explanation about what a segmentation fault is, see What is a segmentation fault?.

Here are the most common reasons for a segmentation fault error. Again, these should be used in diagnosing an existing segfault. To learn how to avoid them, learn your language's undefined behaviors.

This list is also no replacement for doing your own debugging work. (See that section at the bottom of the answer.) These are things you can look for, but your debugging tools are the only reliable way to zero in on the problem.


Accessing a NULL or uninitialized pointer

If you have a pointer that is NULL (ptr=0) or that is completely uninitialized (it isn't set to anything at all yet), attempting to access or modify using that pointer has undefined behavior.

int* ptr = 0;
*ptr += 5;

Since a failed allocation (such as with malloc or new) will return a null pointer, you should always check that your pointer is not NULL before working with it.

Note also that even reading values (without dereferencing) of uninitialized pointers (and variables in general) is undefined behavior.

Sometimes this access of an undefined pointer can be quite subtle, such as in trying to interpret such a pointer as a string in a C print statement.

char* ptr;
sprintf(id, "%s", ptr);

See also:


Accessing a dangling pointer

If you use malloc or new to allocate memory, and then later free or delete that memory through pointer, that pointer is now considered a dangling pointer. Dereferencing it (as well as simply reading its value - granted you didn't assign some new value to it such as NULL) is undefined behavior, and can result in segmentation fault.

Something* ptr = new Something(123, 456);
delete ptr;
std::cout << ptr->foo << std::endl;

See also:


Stack overflow

[No, not the site you're on now, what is was named for.] Oversimplified, the "stack" is like that spike you stick your order paper on in some diners. This problem can occur when you put too many orders on that spike, so to speak. In the computer, any variable that is not dynamically allocated and any command that has yet to be processed by the CPU, goes on the stack.

One cause of this might be deep or infinite recursion, such as when a function calls itself with no way to stop. Because that stack has overflowed, the order papers start "falling off" and taking up other space not meant for them. Thus, we can get a segmentation fault. Another cause might be the attempt to initialize a very large array: it's only a single order, but one that is already large enough by itself.

int stupidFunction(int n)
{
   return stupidFunction(n);
}

Another cause of a stack overflow would be having too many (non-dynamically allocated) variables at once.

int stupidArray[600851475143];

One case of a stack overflow in the wild came from a simple omission of a return statement in a conditional intended to prevent infinite recursion in a function. The moral of that story, always ensure your error checks work!

See also:


Wild pointers

Creating a pointer to some random location in memory is like playing Russian roulette with your code - you could easily miss and create a pointer to a location you don't have access rights to.

int n = 123;
int* ptr = (&n + 0xDEADBEEF); //This is just stupid, people.

As a general rule, don't create pointers to literal memory locations. Even if they work one time, the next time they might not. You can't predict where your program's memory will be at any given execution.

See also:


Attempting to read past the end of an array

An array is a contiguous region of memory, where each successive element is located at the next address in memory. However, most arrays don't have an innate sense of how large they are, or what the last element is. Thus, it is easy to blow past the end of the array and never know it, especially if you're using pointer arithmetic.

If you read past the end of the array, you may wind up going into memory that is uninitialized or belongs to something else. This is technically undefined behavior. A segfault is just one of those many potential undefined behaviors. [Frankly, if you get a segfault here, you're lucky. Others are harder to diagnose.]

// like most UB, this code is a total crapshoot.
int arr[3] {5, 151, 478};
int i = 0;
while(arr[i] != 16)
{
   std::cout << arr[i] << std::endl;
   i++;
}

Or the frequently seen one using for with <= instead of < (reads 1 byte too much):

char arr[10];
for (int i = 0; i<=10; i++)
{
   std::cout << arr[i] << std::endl;
}

Or even an unlucky typo which compiles fine (seen here) and allocates only 1 element initialized with dim instead of dim elements.

int* my_array = new int(dim);

Additionally it should be noted that you are not even allowed to create (not to mention dereferencing) a pointer which points outside the array (you can create such pointer only if it points to an element within the array, or one past the end). Otherwise, you are triggering undefined behaviour.

See also:


Forgetting a NUL terminator on a C string.

C strings are, themselves, arrays with some additional behaviors. They must be null terminated, meaning they have an \0 at the end, to be reliably used as strings. This is done automatically in some cases, and not in others.

If this is forgotten, some functions that handle C strings never know when to stop, and you can get the same problems as with reading past the end of an array.

char str[3] = {'f', 'o', 'o'};
int i = 0;
while(str[i] != '\0')
{
   std::cout << str[i] << std::endl;
   i++;
}

With C-strings, it really is hit-and-miss whether \0 will make any difference. You should assume it will to avoid undefined behavior: so better write char str[4] = {'f', 'o', 'o', '\0'};


Attempting to modify a string literal

If you assign a string literal to a char*, it cannot be modified. For example...

char* foo = "Hello, world!"
foo[7] = 'W';

...triggers undefined behavior, and a segmentation fault is one possible outcome.

See also:


Mismatching Allocation and Deallocation methods

You must use malloc and free together, new and delete together, and new[] and delete[] together. If you mix 'em up, you can get segfaults and other weird behavior.

See also:


Errors in the toolchain.

A bug in the machine code backend of a compiler is quite capable of turning valid code into an executable that segfaults. A bug in the linker can definitely do this too.

Particularly scary in that this is not UB invoked by your own code.

That said, you should always assume the problem is you until proven otherwise.


Other Causes

The possible causes of Segmentation Faults are about as numerous as the number of undefined behaviors, and there are far too many for even the standard documentation to list.

A few less common causes to check:


DEBUGGING

Firstly, read through the code carefully. Most errors are caused simply by typos or mistakes. Make sure to check all the potential causes of the segmentation fault. If this fails, you may need to use dedicated debugging tools to find out the underlying issues.

Debugging tools are instrumental in diagnosing the causes of a segfault. Compile your program with the debugging flag (-g), and then run it with your debugger to find where the segfault is likely occurring.

Recent compilers support building with -fsanitize=address, which typically results in program that run about 2x slower but can detect address errors more accurately. However, other errors (such as reading from uninitialized memory or leaking non-memory resources such as file descriptors) are not supported by this method, and it is impossible to use many debugging tools and ASan at the same time.

Some Memory Debuggers

  • GDB | Mac, Linux
  • valgrind (memcheck)| Linux
  • Dr. Memory | Windows

Additionally it is recommended to use static analysis tools to detect undefined behaviour - but again, they are a tool merely to help you find undefined behaviour, and they don't guarantee to find all occurrences of undefined behaviour.

If you are really unlucky however, using a debugger (or, more rarely, just recompiling with debug information) may influence the program's code and memory sufficiently that the segfault no longer occurs, a phenomenon known as a heisenbug.

In such cases, what you may want to do is to obtain a core dump, and get a backtrace using your debugger.

user12986714
  • 741
  • 2
  • 8
  • 19
CodeMouse92
  • 6,840
  • 14
  • 73
  • 130
  • 4
    On what architecture can you get a segfault from reading uninitialized memory? – Brian Bi Oct 09 '15 at 21:32
  • Maybe I'm using the wrong word? It's a community wiki, so you're welcome to edit. – CodeMouse92 Oct 09 '15 at 21:33
  • 2
    While it is definitely possible to get a segfault by reading past the end of an array, I'd say that it is very unlikely. It has to be on the boundary of a mapped page of VAS, or you'd have to read *a lot* past the end. – sbabbi Oct 09 '15 at 21:37
  • It's definitely in the realm of **undefined behavior**, and a segfault is just one of many nasal demons. I found a few cases of that on questions around SO. – CodeMouse92 Oct 09 '15 at 21:38
  • Trap does not imply a segfault is reported as the error, does it? – Brian Bi Oct 09 '15 at 22:10
  • Don't forget - dereferencing a pointer variable you never bothered to initialize – Arlie Stephens Oct 09 '15 at 22:12
  • @ArlieStephens, please edit the wiki answer here with that! Thanks. – CodeMouse92 Oct 09 '15 at 22:18
  • @JasonMc92 This answer? I just presumed I didn't have sufficient privilege to edit it. Or am I managing not to see a wiki link that's actually under my nose? – Arlie Stephens Oct 09 '15 at 22:41
  • 1
    This answer. If you have at least 100 reputation points, you can click "Edit" on it. This is called a "community wiki", meaning it is maintained by everyone. – CodeMouse92 Oct 09 '15 at 22:43
  • 1
    You can't "trigger" or "cause" undefined behaviour. When you write such code the code _has_ undefined behaviour. Its behaviour is undefined. It's the potential symptoms that you trigger. – Lightness Races in Orbit Oct 10 '15 at 00:23
  • I'm pretty happy with this in general, though. +1 BTW community wiki is pretty much dead nowadays but nice thought! – Lightness Races in Orbit Oct 10 '15 at 00:23
  • It was a real kicker actually writing all of that code and testing it out to make sure the UB was the only problem. – CodeMouse92 Oct 10 '15 at 00:31
  • 1
    A C string technically doesn't need a null terminator. You can treat it like any other type of array and keep a size variable. But you are right that using a non null terminated C string in an algorithm that expected it to be null terminated is undefined – NathanOliver Oct 10 '15 at 01:34
  • @NathanOliver, true enough if you're treating it as an array, but typically when we start working with it as a "string" (as in, how we're treating it), many assume they can use the c-string functions with it, and as you mentioned, therein we get a lot of UB. – CodeMouse92 Oct 10 '15 at 01:37
  • @ShafikYaghmour, please add that link to the answer. (It's a community wiki) – CodeMouse92 Oct 10 '15 at 01:46
  • 1
    In my experience, accessing a dangling pointer almost never causes a segmentation fault, unfortunately. That's why such bugs are amongst the most difficult to find. – alain Oct 13 '15 at 20:05
  • @alain, yes, same here. However, it's a common mistake that has undefined behavior, of which one of those could potentially be a segfault. That's why it's on the list. – CodeMouse92 Oct 13 '15 at 20:11
  • Yes but not directly.. A dangling pointer is inside the address space of the program, so reading it does not trigger a segfault. Many times the values read are not even garbage, sometimes they are, and then they cause *other* problems *somewhere else* in the code. But ok, the can be 'the root problem' that caused the segfault. – alain Oct 13 '15 at 20:21
  • Ah, well, you're welcome to [edit] and clarify that in the answer. – CodeMouse92 Oct 13 '15 at 20:22
  • 2
    @NathanOliver: I think a "C-string" is precisely that: a null-terminated `char` array intended to be used with C's string functions. Of course not all `char` arrays need be null terminated, but then I don't think you'd call them C-strings otherwise. – Lightness Races in Orbit Oct 15 '15 at 18:54
  • 1
    @JohnChesterfield, you'd be interested to know that the debugger "fixing" the UB is known as a "heisenbug" - see link in answer. – CodeMouse92 Oct 16 '15 at 20:45
  • I don't believe that adding symbols to an executable fixes the "heisenbug". The symbols are not even read from disk when loading a program. What is true is that the debugger often initializes data sections differently and you cannot debug your code because it just works when running with the debugger. – Jean-François Fabre Nov 10 '16 at 20:35
  • @Jean-FrançoisFabre, that's perhaps a more precise way to word that, yes. It's just hard to know for sure *why* heisenbugs occur. – CodeMouse92 Nov 10 '16 at 21:28
  • what can happen is that the program works or not depending on other programs being launched, the return values of malloc, etc. – Jean-François Fabre Nov 10 '16 at 21:29
  • @Jean-FrançoisFabre, sometimes, yes. There have actually been cases of *just* compiling with `-g`, without even starting the debugger, obscuring the segfault. – CodeMouse92 Nov 10 '16 at 21:31
  • 1
    "*WARNING: If you have a case of this and it isn't throwing an error, do NOT take that to mean you can get away with it.*" This needs to be moved to the top and bolded, because it holds for all of them. Just because I do something that looks like UB and I don't get a segfault doesn't mean it's OK, and that's true of each of the points listed here. Admittedly, some are more likely to raise errors than others, but still. – Nic Mar 16 '17 at 21:50
  • @QPaysTaxes, good idea. It is a community wiki, so go ahead and edit it. :) – CodeMouse92 Mar 16 '17 at 21:56
  • `kill(getpid(), SIGSEG)`, but in more seriousness, one of the most common reasons in large code is writing to heap memory after freeing it. _This usually causes the segfault somewhere else, in apparently harmless code._ – Joshua May 04 '20 at 03:42