1
votes

I know that segfault is a common manifestation of undefined behavior. But I have two small questions about it:

  1. Are ALL segfaults undefined behavior?

  2. If no, is there any way to ensure a segfault?

What is a segmentation fault? is far more general than my question and none of the answers answers any of my questions.

4
Possible duplicate of What is a segmentation fault?Hazim
The classic example of this is to dereference a NULL pointer, ie. assign something to address zero from a user program. (Doing so is not a guarantee of that behavior on all particular platforms with all particular compilers)Ben Zotto
The C standard does not define segmentation faults. It refers to traps, which C implementations can implement in various ways. And I do not believe there is anything in the C standard that guarantees a trap. There are system-specific ways to generate a segmentation fault. One would be to allocate a page of memory, then change its protection to deny yourself access, then access it.Eric Postpischil
The question needs some context. In Standard C there is no such way. But for a particular implementation there might be (and it would be far too broad to try and survey all implementations)M.M
@M.M I guess that means that the answer to my second question is a simple "no" :)klutt

4 Answers

5
votes

A segmentation fault simply means that you did an invalid access to memory -- either because the address requested is not mapped (mapping error) or because you don't have permissions to access it (access error).

  1. There are segmentation faults that are intended. One such example can be found here -- a mini application that deliberately plays with permissions of memory pages in order to detect where writes are being made by a given function.

  2. The easiest way is to use the raise function.

Source:

#include <signal.h>    
int main() {
    raise(SIGSEGV);
    return 0;
}
3
votes
  1. Are ALL segfaults undefined behavior?

This question is trickier than it might seem, because "undefined behavior" is a description of either a C source program, or the result of running a C program in the "abstract machine" that describes behavior of C programs in general; but "segmentation fault" is a possible behavior of a particular operating system, often with help from particular CPU features.

The C Standard doesn't say anything at all about segmentation faults. The one nearly relevant thing it does say is that if a program execution does not have undefined behavior, then a real implementation's execution of the program will have the same observable behavior as the abstract machine's execution. And "observable behavior" is defined to include just accesses to volatile objects, data written into files, and input and output of interactive devices.

If we can assume that a "segmentation fault" always prevents further actions by a program, then any segmentation fault without the presence of undefined behavior could only happen after all of the observable behavior has completed as expected. (But note that valid optimizations can sometimes cause things to happen in a different order from the obvious one.)

So a situation where a program causes a segmentation fault (for the OS) although there is no undefined behavior (according to the C Standard) doesn't make much sense for a real compiler and OS, but we can't rule it out completely.

But also, all that is assuming perfect computers. If RAM is bad, an intended address value might end up changed. There are even very infrequent but measurable events where cosmic rays can change a bit within otherwise good RAM. Soft errors like those could cause a segmentation fault (on a system where "segmentation fault" is a thing), for practically any perfectly written C program, with no undefined behavior possible on any implementation or input.

  1. If no, is there any way to ensure a segfault?

That depends on the context, and what you mean by "ensure".

Can you write a C program that will always cause a segfault? No, because some computers might not even have such a concept.

Can you write a C program that always causes a segfault if it is possible on a computer? No, because some compilers might do things to avoid the actual problem in some cases. And since the program's behavior is undefined, not causing a segfault is just as valid a result as causing a segfault. In particular, one real obstacle you might run into, doing even simple things like deliberately dereferencing a null pointer value, is that compiler optimizations sometimes assume that the inputs and logic will always turn out so that undefined behavior will not happen, since it's okay to not do what the program says for inputs that do lead to undefined behavior.

Knowing details about how one specific OS, and possibly the CPU, handle memory and sometimes generate segmentation faults, can you write assembly instructions that will always cause a segfault? Certainly, if the segfault handling is of any value at all. Can you write a C program that will trigger a segfault in roughly the same manner? Most probably.

2
votes

You can never go wrong with dereferencing a NULL pointer.

int main() {
  int *a = 0;
  *a = 0;
  return 0;
}

As the comments rightfully mention, this will not work 100% of the time and is platform specific. But it should work in most common platforms.

1
votes

Assuming the platform supports segfaults at all, here are some possibilities:

  • Use raise. This will produce noticeably a different siginfo_t, but often that doesn't matter.
  • Dereference a non-volatile pointer. This is likely to be optimized out as "unreachable".
  • Dereference a volatile pointer. This should prevent the compiler from optimizing out the access.
  • Use asm volatile and dereference a pointer. Be sure to include a phony output that is later used, otherwise the compiler can still perform unwanted optimizations. This requires special code for each platform.
  • Build a kernel module that directly produces a SIGSEGV with appropriate siginfo_t. This assumes kernel modules even can be loaded (or even compiled).

If we're dereferencing a pointer, do we:

  • read through it, or
  • write through it, or
  • both?

and, what pointer should it be?

  • NULL is a popular choice, but it is sometimes possible for that page to be mapped. Security-conscious kernels generally disallow this, these days.
  • Use a valid, but misaligned, pointer. This is highly platform dependent, and probably produces a different siginfo_t. Maybe even a SIGBUS or something.
  • Use a misaligned pointer that straddles pages, of which one page is unmapped or protected, as below.
  • call mmap with protection that forbids that access you're attempting. I don't remember if this siginfo_t is distinguishable or not. Can race, but only if some other thread in the program is hostile. It is also possible for the mmap to fail.
  • call mmap followed immediately by munmap, then dereference the pointer. In single-threaded programs with signals blocked, this can produce an address that is guaranteed not to be mapped. However, it may race in multi-threaded programs, and it is possible for the initial mmap to fail.
  • call mmap in a loop until it fails because you've exhausted the kernel's 64k limit on number of mapped memory regions. Then parse /proc/self/maps and find an address that isn't covered by any of them. This might be racy if other threads are currently munmaping. If other threads are currently mmaping, they may fail in mysterious ways before your segfault kills the process.

In summary, there is no perfectly reliable/portable method, but there are plenty that are good enough.