Segmentation fault (core dumped) (tested)
Segmentation fault means your program touched memory it isn't allowed to touch, and the kernel killed it with SIGSEGV. The optional (core dumped) suffix just means the shell also wrote a core file. We reproduced both the crash and the suffix on a real box to show exactly when each appears.
1. What actually happens
A segmentation fault is the kernel stopping a process that tried to read or write memory it doesn't own, most often through a null or wild pointer. The kernel sends the process signal 11 (SIGSEGV). The process usually has no handler for it, so it dies, and the shell that started it prints a message.
We wrote this minimal C program:
#include <stdio.h>
int main(void) {
int *p = NULL;
printf("before crash\n");
fflush(stdout);
*p = 42;
printf("never gets here\n");
return 0;
}
Compiled with gcc -O0 -g -o segfault segfault.c on gcc 14.2.0, no warnings. Writing through p dereferences a null pointer, which is unmapped memory, so the kernel delivers SIGSEGV.
2. The exact shell output we measured
Running the compiled binary under bash gave:
$ ./segfault
before crash
Segmentation fault (core dumped)
$ echo $?
139
With core dumps disabled (ulimit -c 0, the box's default) the same crash printed:
$ ulimit -c 0
$ ./segfault
before crash
Segmentation fault
$ echo $?
139
Only the trailing (core dumped) changes. The job-control line bash shows ([1]+ Segmentation fault (core dumped) ./segfault) also includes a job number and PID when the process is backgrounded; in a plain foreground run bash just prints Segmentation fault with or without the suffix. We confirmed the same two outputs under dash (Debian's /bin/sh), so this is shell-independent: it's controlled by the resource limit, not the shell.
Exit code was 139 in every run. That is the standard 128 + signal number convention: 128 + 11 (SIGSEGV) = 139. This is how scripts and CI detect a segfault reliably, since the text message can vary by shell and locale but the exit code does not.
3. What controls "(core dumped)"
The suffix appears only if two things are both true: the process's core resource limit allows a dump, and the kernel successfully wrote one. We tested both settings in the same shell session:
| Setting | Command | Shell output | Core file written? |
|---|---|---|---|
| Disabled (box default) | ulimit -c 0 | Segmentation fault | No |
| Enabled | ulimit -c unlimited | Segmentation fault (core dumped) | Yes, 438272 bytes |
We checked ulimit -c before changing anything: it was 0 by default on this box, which is why most interactive shells only ever show the plain Segmentation fault message unless something has raised the limit.
After ulimit -c unlimited, the crash left a real file named core.<pid> (for example core.2098362) in the current directory. That naming and location come from /proc/sys/kernel/core_pattern, which on this box was the plain default core (pattern core.%p is common too; check your own box, don't assume). file core.2098362 confirmed it: ELF 64-bit LSB core file, x86-64 ... from './segfault'.
Some distros point core_pattern at systemd-coredump instead of a plain file (a line starting with | and a path like /usr/lib/systemd/systemd-coredump). This box does not: core_pattern was the literal string core, and the coredumpctl command was not installed, so dumps land as ordinary files you inspect with gdb or file directly, not through coredumpctl.
4. Reproduce it yourself
cat > segfault.c <<'EOF'
int main(void) { int *p = 0; *p = 1; return 0; }
EOF
gcc -O0 -g -o segfault segfault.c
ulimit -c unlimited # enable core dumps for this shell
./segfault
echo $? # 139
ls core.* # the dump, if core_pattern writes plain files
If you have gdb installed, open the dump with gdb ./segfault core.<pid> and run bt for a backtrace showing the crashing line. On systems that route dumps to systemd, use coredumpctl list and coredumpctl debug instead of a bare filename.
5. Common real causes
- Null pointer dereference. Exactly what we reproduced: reading or writing through a pointer that is
NULLor was never initialized. - Use-after-free. Writing to memory already released by
free(); the mapping may still exist until something else overwrites it, so it can crash later and unpredictably. - Buffer overrun. Writing past the end of an array walks into memory the process doesn't own.
- Stack overflow from deep or infinite recursion. Each call frame needs stack space; past the limit, the next push hits unmapped memory.
- Mismatched types across a library boundary. Calling a function pointer with the wrong signature, or a mismatched struct layout between a program and a shared library it links.
6. How to actually debug one
- Compile with
-g(debug symbols) and without optimization (-O0) while you investigate; optimized code can reorder or inline things so the crash line in a backtrace is misleading. - Enable core dumps for the session:
ulimit -c unlimited, then reproduce the crash and load the resulting file ingdb. - Or run the program directly under
gdb --args ./yourprogram args...and typerun; gdb stops at the fault andbtshows the call stack immediately, no core file needed. - For memory bugs that don't always crash (use-after-free, off-by-one), rebuild with
-fsanitize=address(AddressSanitizer); it reports the exact bad access with a stack trace instead of waiting for a segfault. - In scripts and CI, check for exit code 139 rather than matching the text message, since the text depends on the shell and
ulimit -cstate.
Frequently asked questions
What does "Segmentation fault (core dumped)" actually mean?
The kernel killed your process with SIGSEGV because it accessed memory it wasn't allowed to. "(core dumped)" just means a memory snapshot (a core file) was also written, which only happens if ulimit -c allows it. We measured both: the fault text is identical either way, only the suffix changes.
Why don't I see "(core dumped)" on my machine?
Because your shell's core size limit is 0 by default, which is what we found on this Debian 13 box with ulimit -c. Run ulimit -c unlimited first, then reproduce the crash, and the suffix appears along with an actual core.<pid> file.
What exit code does a segfault produce?
139, which we confirmed in every run. That's 128 + 11, where 11 is SIGSEGV's signal number. Checking for 139 in scripts is more reliable than matching the printed text, since the text varies by shell.
Where does the core file go?
Wherever /proc/sys/kernel/core_pattern says. We found the plain pattern "core" on this box, so files appeared as core.<pid> in the working directory. Some distros instead pipe dumps to systemd-coredump, in which case you list and inspect them with coredumpctl rather than looking for a file.
Does the shell matter, e.g. bash vs sh?
No. We reproduced the identical pair of outputs, Segmentation fault and Segmentation fault (core dumped), under both bash and dash (Debian's /bin/sh). The deciding factor is the process's core resource limit, not which shell launched it.
Written with AI assistance. Measured on 2026-10-02 on Debian GNU/Linux 13 (trixie), gcc 14.2.0, bash 5.x and dash, kernel 6.12.107+deb13-amd64. Compiled a tiny C program with a null-pointer write and ran it under both ulimit -c 0 and ulimit -c unlimited. PlainHeaders is our extension; gcc, bash and dash are free.