Question

Bus Error vs Segmentation Fault in C: SIGBUS and SIGSEGV Explained

cunixsegmentation-faultbus-error

Question

What does a bus error message mean, and how does it differ from a segmentation fault?

Short Answer

A bus error and a segmentation fault are both abnormal program terminations caused by invalid memory operations. In C and Unix-like systems, they usually correspond to the signals SIGBUS and SIGSEGV, but they describe different categories of memory-access problems. By the end of this page, you will know the usual causes of each error, how platform behavior can vary, and how to investigate crashes with debugging tools.

Concept

A program does not directly control all computer memory. The operating system and CPU enforce rules about which memory addresses a process may access and how those addresses may be used.

When code breaks one of those rules, the CPU raises a hardware exception. On Unix-like systems, the operating system commonly delivers a signal to the process:

  • Segmentation fault (SIGSEGV): the program accessed memory that is not mapped into its address space, or used memory with prohibited permissions.
  • Bus error (SIGBUS): the program made an access that the hardware or operating system cannot complete for another memory-related reason, such as an alignment requirement or an invalid region of a memory-mapped file.

The exact boundary is platform-dependent. A mistake that produces SIGBUS on one CPU or operating system may produce SIGSEGV on another. Therefore, treat the message as an important clue, not as a complete diagnosis.

In C, both errors are often symptoms of undefined behavior: the program has performed an operation that the C language does not define safely. The crash may happen at the bad line, later, or not at all in a different build.

Mental Model

Imagine your process has a rented office building.

  • A segmentation fault is like trying to enter a room that is not part of your building, or trying to write on a wall marked “read-only.” Security stops you because you do not have permission.
  • A bus error is like entering a room you are allowed to use but trying to plug equipment into a connector in an unsupported way, or using a storage room whose floor has disappeared. The location may exist, but the requested access cannot be completed correctly.

Both are serious access failures. The difference is mainly why the machine rejected the memory operation.

Take Quiz

Syntax and Examples

In C, these failures are usually not values you check with if. They are signals raised after an invalid access. The goal is to write code that validates pointers, array bounds, object lifetimes, and I/O results before accessing memory.

A common cause of a segmentation fault is dereferencing a null pointer:

#include <stdio.h>

int main(void) {
    int *number = NULL;
    printf("%d\n", *number);  // Invalid: number points nowhere.
    return 0;
}

A safer version ensures the pointer refers to a real object before dereferencing it:

#include <stdio.h>

int main(void) {
    int number = 42;
    int *pointer = &number;

    if (pointer != NULL) {
        printf("%d\n", *pointer);
    }

    return 0;
}

pointer contains the address of number, so *pointer is a valid access.

An alignment-related bus error can occur on systems that require values to begin at particular address boundaries. This is a risky example:

char bytes[sizeof(int) + 1];
int *value = (int *)(bytes + 1);  // May be misaligned; dereferencing is undefined behavior.

Do not use pointer casts to reinterpret arbitrary byte storage as another type. If you need to copy bytes into an int, use memcpy:

#include <string.h>

int value;
unsigned char bytes[sizeof value] = {0};
memcpy(&value, bytes, sizeof value);

memcpy avoids an invalidly aligned int * dereference.

Step by Step Execution

Consider this program:

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int *scores = malloc(3 * sizeof *scores);
    if (scores == NULL) {
        return 1;
    }

    scores[0] = 10;
    scores[1] = 20;
    scores[2] = 30;

    free(scores);
    printf("%d\n", scores[0]);
    return 0;
}

Step by step:

  1. malloc reserves space for three int values and returns its address in scores.
  2. The null check handles the possibility that allocation failed.
  3. The assignments to indexes 0, 1, and 2 are valid while the allocation is alive.
  4. free(scores) releases that allocation. The pointer variable still contains an old address, but the program no longer owns or may access that memory.
  5. scores[0] dereferences a dangling pointer. This is use-after-free, which is undefined behavior.
  6. The program might appear to print 10, print an unrelated value, crash with SIGSEGV, or fail in a different way. The C language does not guarantee any result.

A useful defensive habit is to clear a pointer after freeing it:

free(scores);
scores = NULL;

This does not repair code that tries to use the data later, but it makes an accidental second free(scores) safe and can make invalid use easier to detect during review.

Real World Use Cases

These crashes frequently appear in practical software:

  • Parsing files or network packets: Reading a length field incorrectly can lead to an out-of-bounds array access and a segmentation fault.
  • Memory-mapped files: A program can map a file with mmap, then access a mapped page whose underlying file was truncated. On many Unix-like systems, this can cause SIGBUS.
  • Embedded systems: Some processors strictly enforce alignment. Reading a multi-byte value through a wrongly aligned pointer can cause a bus error.
  • Image, audio, and database processing: Large buffers make index and size-calculation mistakes more likely.
  • Native extensions and libraries: C or C++ code called from another runtime can corrupt memory; the visible crash may occur far from the original bug.
  • Concurrent programs: One thread may free or modify memory while another thread still uses it, resulting in an invalid access.
Take Quiz

Real Codebase Usage

Production C code reduces these failures through explicit checks and clear ownership rules.

Guard clauses for pointers and inputs

int copy_name(char *destination, size_t capacity, const char *source) {
    if (destination == NULL || source == NULL || capacity == 0) {
        return -1;
    }

    snprintf(destination, capacity, "%s", source);
    return 0;
}

The function rejects invalid arguments before using them.

Bounds validation

int read_score(const int *scores, size_t count, size_t index, int *result) {
    if (scores == NULL || result == NULL || index >= count) {
        return -1;
    }

    *result = scores[index];
    return 0;
}

Checking index >= count prevents accessing beyond the array.

Ownership conventions

Teams document who owns allocated memory and who must call free. A common convention is: a function that allocates and returns a pointer transfers ownership to its caller. The caller frees it exactly once.

Debug builds and tools

Developers commonly compile with warnings and sanitizers:

cc -Wall -Wextra -Wpedantic -g -fsanitize=address,undefined program.c -o program
./program

AddressSanitizer can identify many out-of-bounds and use-after-free errors. UndefinedBehaviorSanitizer can detect many invalid operations. These tools do not replace correct code, but they often locate the original error much more effectively than a crash message alone.

For a crash, a debugger can show the failing stack frame:

gdb ./program
(gdb) run
(gdb) bt

The bt command prints a backtrace. Inspect the frame where the invalid access occurred, then trace where its pointer, index, or size came from.

Common Mistakes

Assuming every invalid pointer causes the same signal

Do not write logic that depends on receiving SIGBUS rather than SIGSEGV. Signal choice can vary by operating system, CPU architecture, memory layout, and the specific failure.

Dereferencing before checking malloc

Broken:

int *items = malloc(count * sizeof *items);
items[0] = 1;  // Invalid if malloc returned NULL.

Better:

int *items = malloc(count * sizeof *items);
if (items == NULL && count != 0) {
    return 1;
}

Reading outside array bounds

Broken:

int values[3] = {1, 2, 3};
printf("%d\n", values[3]);  // Valid indexes are 0, 1, and 2.

Use index < count before indexing.

Using memory after free

Broken:

free(items);
items[0] = 7;

After free, do not read, write, or free the allocation again. Redesign the control flow so all required work happens before the release.

Confusing a pointer with allocated storage

This creates an uninitialized pointer; it does not create an int:

int *value;
*value = 5;  // Undefined behavior.

Either use a normal object (int value = 5;) or point to one (int *pointer = &value;).

Casting arbitrary bytes and dereferencing them

A cast does not guarantee correct alignment, object lifetime, or type compatibility. Prefer memcpy when converting between raw bytes and a value type.

Treating a signal handler as a recovery mechanism

Catching SIGSEGV or SIGBUS rarely makes it safe to continue. Program state may already be corrupted. Use handlers only for narrowly designed tasks such as logging or controlled shutdown, and fix the invalid access.

Comparisons

AspectSegmentation fault (SIGSEGV)Bus error (SIGBUS)
General meaningInvalid virtual-memory address or access permission violationMemory access that cannot be completed for hardware or OS-specific reasons
Common causesNull/dangling pointer dereference, out-of-bounds access, writing read-only memoryMisaligned access on strict CPUs, invalid memory-mapped file access
Relation to CUsually the result of undefined behaviorUsually the result of undefined behavior or an invalid mapped-file condition
Platform behaviorCommon on Unix-like systemsMeaning and frequency vary more across platforms
Debugging approachCheck pointer validity, lifetime, bounds, and permissionsAlso check alignment and mmap/file size conditions

SIGSEGV and SIGBUS are signals, not C exceptions. Ordinary C code does not use try/catch to handle them. Prevent the faulty access, then use debuggers and sanitizers to locate its cause.

Take Quiz

Cheat Sheet

  • Bus error usually means the OS delivered SIGBUS after a memory access could not be completed.
  • Segmentation fault usually means the OS delivered SIGSEGV after an unmapped or forbidden memory access.
  • Signal details are platform-dependent; do not rely on a specific signal for program logic.
  • Frequent SIGSEGV causes: null pointers, dangling pointers, array overflows, stack overflows, writes to read-only memory.
  • Frequent SIGBUS causes: strict alignment violations and invalid access to a memory-mapped file.
  • After free(ptr), do not dereference ptr; optionally set it to NULL.
  • Before array[index], ensure index < element_count.
  • Check allocation results when allocation may fail.
  • Compile for debugging:
cc -Wall -Wextra -Wpedantic -g -fsanitize=address,undefined file.c -o file
  • Investigate crashes with gdb, especially run and bt.

FAQ

Is a bus error the same as a segmentation fault?

No. Both are memory-related crash signals, but they generally indicate different reasons an access failed. The exact distinction varies by platform.

What causes a bus error in C?

Common causes include accessing incorrectly aligned data on systems that enforce alignment and accessing invalid pages of a memory-mapped file. Some systems use SIGBUS for other low-level memory faults as well.

What causes a segmentation fault in C?

Typical causes are dereferencing NULL, accessing an array outside its bounds, using freed memory, and writing to memory without write permission.

Can an array out-of-bounds error cause either signal?

Yes. Out-of-bounds access is undefined behavior. It may cause SIGSEGV, SIGBUS, corrupt data silently, or appear to work temporarily.

Why does my program crash on one computer but not another?

Undefined behavior depends on details such as CPU architecture, compiler choices, optimization level, operating system memory layout, and timing. A lack of crash does not mean the code is correct.

How do I find the line that caused the crash?

Compile with debug symbols (-g), reproduce the crash in gdb, and run bt for a backtrace. AddressSanitizer is often even more direct for common memory bugs.

Can I safely catch SIGSEGV or SIGBUS and keep running?

Usually no. The program may be in an inconsistent state, and continuing can cause further corruption. Find and fix the invalid memory access instead.

Take Quiz

Mini Project

Description

Build a small C program that safely reads a score from a dynamically allocated array. The project practices the checks that prevent common segmentation faults: validating allocation, checking array bounds, and avoiding use-after-free.

Goal

Create a program that prints a requested score when the index is valid and reports an error when it is not.

Requirements

  • Allocate storage for five integer scores.
  • Initialize all five scores.
  • Read one requested index from the command line.
  • Reject missing, invalid, negative, or out-of-range indexes.
  • Free the allocated memory exactly once before exiting.
Take Quiz

Keep learning

Related questions

View more