Apa itu kesalahan segmentasi?

599

Apa itu kesalahan segmentasi? Apakah berbeda dalam C dan C ++? Bagaimana kesalahan segmentasi dan pointer menggantung terkait?

Rajendra Uppal
sumber
95
kesalahan segmentasi membuat kompiler terasa buruk .
Benjamin Crouzier
22
Jika itu masalahnya, mengapa dalam kasus saya kompiler tidak mengeluh apa-apa, semuanya berjalan lancar, tetapi pada saat dijalankan sistem melempar kesalahan segmentasi (dump inti)? T_T
Jim Raynor
3
Hanya dump memori ketika ada masalah!
resultsway
7
@ Pinouchon: Lucu, tapi kapan kompiler ada hubungannya dengan kesalahan seg? Bukankah ini lebih merupakan run time enviroment?
dhein
1
Biasanya dipanggil dengan mencoba melakukan dereferensi pointer nol, sehingga kesalahan segmentasi sering dianalogikan dengan Java NullPointerException.
Raedwald

Jawaban:

674

Kesalahan segmentasi adalah jenis kesalahan khusus yang disebabkan oleh mengakses memori yang "bukan milik Anda." Ini adalah mekanisme pembantu yang mencegah Anda dari merusak memori dan memperkenalkan bug memori yang sulit di-debug. Setiap kali Anda mendapatkan segfault, Anda tahu Anda melakukan sesuatu yang salah dengan memori - mengakses variabel yang telah dibebaskan, menulis ke bagian read-only dari memori, dll. Kesalahan segmentasi pada dasarnya sama di sebagian besar bahasa yang memungkinkan Anda mengacaukan manajemen memori, tidak ada perbedaan utama antara segfault di C dan C ++.

Ada banyak cara untuk mendapatkan segfault, setidaknya dalam bahasa tingkat rendah seperti C (++). Cara umum untuk mendapatkan segfault adalah dengan melakukan dereferensi pointer nol:

int *p = NULL;
*p = 1;

Segfault lain terjadi ketika Anda mencoba menulis ke sebagian memori yang ditandai sebagai hanya-baca:

char *str = "Foo"; // Compiler marks the constant string as read-only
*str = 'b'; // Which means this is illegal and results in a segfault

Pointer yang menggantung menunjuk ke sesuatu yang tidak ada lagi, seperti di sini:

char *p = NULL;
{
    char c;
    p = &c;
}
// Now p is dangling

Pointer pmenggantung karena menunjuk ke variabel karakter cyang tidak ada lagi setelah blok berakhir. Dan ketika Anda mencoba dereference pointer menggantung (seperti *p='A'), Anda mungkin akan mendapatkan segfault.

zoul
sumber
154
Contoh terakhir sangat tidak menyenangkan, ketika saya membangun: int main () {char * p = 0; {char c = 'x'; p = & c; } printf ("% c \ n", * p); return 0; } Dengan gcc atau beberapa kompiler lain, tampaknya 'berfungsi'. Tidak ada peringatan saat kompilasi. Tidak ada kesalahan. Ini karena '}' di luar ruang lingkup, tidak benar-benar menghapus data, cukup tandai sebagai bebas untuk digunakan lagi. Kode dapat berjalan dengan baik pada sistem produksi selama bertahun-tahun, Anda mengubah bagian lain dari kode, mengubah kompiler atau sesuatu yang lain dan BOOOOOM!
Chris Huang-Leaver
36
Maaf atas masalah tetapi hanya catatan samping ... tidak ada contoh Anda yang menyebabkan segfault, bahkan itu hanya perilaku yang tidak terdefinisi ;-)
oldrinb
18
@oldrinb: Tidak mungkin untuk menulis kode yang tentu menyebabkan segfault. Paling tidak karena ada sistem di luar sana yang beroperasi tanpa perlindungan memori, sehingga tidak dapat memastikan apakah sepotong memori benar-benar "milik Anda", dan karenanya tidak tahu segfault, hanya perilaku yang tidak terdefinisi ... (AmigaOS klasik, misalnya)
DevSolar
7
@ ChrisHuang-Leaver, Anda perlu memahami bahwa citu lokal, itu berarti bahwa itu telah didorong pada tumpukan setelah {dan muncul setelah itu }. pointer menggantung hanyalah referensi ke offset yang sekarang keluar dari tumpukan. itu sebabnya mengubahnya dalam program sederhana tidak akan pernah memicu segfault. di sisi lain itu dapat menyebabkan segfault dalam kasus penggunaan yang lebih kompleks, di mana panggilan fungsi lain dapat menyebabkan tumpukan untuk tumbuh dan berisi data yang diarahkan oleh pointer menggantung. menulis ke data itu (vars lokal) akan mengarah pada perilaku yang tidak terdefinisi (segfault & Co)
Ayman Khamouma
3
@ ChrisHuang-Leaver, biasanya ketika Anda keluar dari ruang lingkup, kompiler harus memulihkan beberapa ruang stack untuk membebaskan ruang stack yang tidak digunakan, tetapi ini tidak selalu terjadi (dengan gcc menjadi salah satu dari kompiler ini). Selain itu, ruang stack yang dialokasikan biasanya digunakan kembali, jadi saya belum pernah mendengar ada sistem operasi yang mengembalikan halaman stack yang tidak digunakan ke sistem, membuat ruang tersebut menjadi subjek SIGSEGV, jadi saya tidak akan mengharapkan sinyal seperti itu dari campur aduk dengan stack.
Luis Colorado
111

Perlu dicatat bahwa kesalahan segmentasi tidak disebabkan oleh secara langsung mengakses memori proses lain (ini yang saya dengar kadang-kadang), karena itu tidak mungkin. Dengan memori virtual, setiap proses memiliki ruang alamat virtualnya sendiri dan tidak ada cara untuk mengakses yang lain menggunakan nilai pointer apa pun. Pengecualian untuk ini adalah shared library yang ruang alamat fisiknya sama dipetakan ke (mungkin) alamat virtual dan memori kernel yang berbeda yang bahkan dipetakan dengan cara yang sama di setiap proses (untuk menghindari TLB membilas syscall, saya pikir). Dan hal-hal seperti shmat;) - inilah yang saya anggap sebagai akses 'tidak langsung'. Satu dapat, bagaimanapun, memeriksa bahwa mereka biasanya berada jauh dari kode proses dan kami biasanya dapat mengaksesnya (inilah sebabnya mereka ada di sana,

Namun, kesalahan segmentasi dapat terjadi jika mengakses memori (proses) kita sendiri dengan cara yang tidak benar (misalnya mencoba menulis ke ruang yang tidak dapat ditulisi). Tetapi alasan paling umum untuk itu adalah akses ke bagian ruang alamat virtual yang tidak dipetakan ke fisik sama sekali.

Dan semua ini berkenaan dengan sistem memori virtual.

konrad.kruczynski
sumber
Dengan memori bersama / file yang dipetakan memori dimungkinkan bagi orang lain untuk mengacaukan memori Anda. Di WIN32 ada API jahat seperti 'WriteProcessMemory' juga!
paulm
1
@ paulm: Ya, saya tahu. Ini adalah apa yang ada dalam pikiran saya dalam "Dan hal-hal seperti shmat;) - ini adalah apa yang saya anggap sebagai akses 'tidak langsung'."
konrad.kruczynski
Dalam sistem operasi memori virtual tidak ada cara (biasanya, jadi tolong, pelaksana sistem operasi, jangan nyalakan saya untuk ini) untuk proses mengakses memori virtual proses lain, tidak menjadi semacam panggilan sistem sambungan memori yang memungkinkan Anda untuk mengakses. Alamat memori virtual biasanya memiliki arti yang berbeda tergantung pada proses yang sedang dipertimbangkan.
Luis Colorado
38

Kesalahan segmentasi disebabkan oleh permintaan untuk halaman yang prosesnya tidak terdaftar dalam tabel deskriptornya, atau permintaan yang tidak valid untuk halaman yang telah terdaftar (misalnya permintaan tulis pada halaman read-only).

Pointer menggantung adalah pointer yang mungkin atau mungkin tidak menunjuk ke halaman yang valid, tetapi tidak menunjuk ke segmen memori "tak terduga".

Ignacio Vazquez-Abrams
sumber
10
Ini benar, tetapi apakah itu akan sangat membantu Anda jika Anda belum tahu apa itu kesalahan segmentasi?
zoul
29

Sejujurnya, seperti poster-poster lain sebutkan, Wikipedia memiliki artikel yang sangat bagus tentang ini, jadi silakan lihat di sana. Jenis kesalahan ini sangat umum dan sering disebut hal-hal lain seperti Pelanggaran Akses atau Kesalahan Perlindungan Umum.

Mereka tidak berbeda dalam C, C ++ atau bahasa lain yang memungkinkan pointer. Jenis kesalahan ini biasanya disebabkan oleh pointer

  1. Digunakan sebelum diinisialisasi dengan benar
  2. Digunakan setelah memori yang mereka tunjuk telah dialokasikan kembali atau dihapus.
  3. Digunakan dalam array yang diindeks di mana indeks berada di luar batas array. Ini umumnya hanya ketika Anda melakukan pointer matematika pada array tradisional atau c-string, bukan koleksi berbasis STL / Boost (dalam C ++.)
Komponen 10
sumber
16

Menurut wikipedia:

Kesalahan segmentasi terjadi ketika suatu program mencoba mengakses lokasi memori yang tidak diizinkan untuk diakses, atau mencoba mengakses lokasi memori dengan cara yang tidak diizinkan (misalnya, berusaha menulis ke lokasi baca-saja, atau untuk menimpa bagian dari sistem operasi).

Orhan Cinar
sumber
13

Kesalahan segmentasi juga disebabkan oleh kegagalan perangkat keras, dalam hal ini adalah memori RAM. Ini adalah penyebab yang kurang umum, tetapi jika Anda tidak menemukan kesalahan dalam kode Anda, mungkin memtest dapat membantu Anda.

Solusinya dalam hal ini, ganti RAM.

edit:

Di sini ada referensi: Kesalahan segmentasi oleh perangkat keras

Alejo Bernardin
sumber
3
Tes cepat dan kotor untuk RAM yang salah adalah menjalankan program mogok Anda berulang-ulang dalam satu lingkaran. Jika program tidak memiliki determinasi internal — yaitu, ia selalu menghasilkan output yang sama untuk input yang sama, atau setidaknya seharusnya — tetapi, untuk beberapa input tertentu, kadang-kadang crash , tidak selalu tetapi tidak pernah juga: maka Anda harus mulai khawatir tentang RAM yang buruk.
zwol
8

Kesalahan segmentasi terjadi ketika suatu proses (menjalankan instance dari suatu program) sedang mencoba mengakses alamat memori read-only atau rentang memori yang sedang digunakan oleh proses lain atau mengakses alamat memori yang tidak ada (tidak valid). Masalah Dangling Reference (pointer) berarti mencoba mengakses objek atau variabel yang isinya sudah dihapus dari memori, misalnya:

int *arr = new int[20];
delete arr;
cout<<arr[1];  //dangling problem occurs here
Sohail xIN3N
sumber
4
Cara yang benar untuk menghapus array adalah delete [] arr;
Damian
8

Halaman Segmentation_fault Wikipedia memiliki deskripsi yang sangat bagus tentang itu, hanya menunjukkan penyebab dan alasannya. Lihat wiki untuk mendapatkan deskripsi terperinci.

Dalam komputasi, kesalahan segmentasi (sering disingkat menjadi segfault) atau pelanggaran akses adalah kesalahan yang ditimbulkan oleh perangkat keras dengan perlindungan memori, memberitahukan sistem operasi (OS) tentang pelanggaran akses memori.

Berikut ini adalah beberapa penyebab khas kesalahan segmentasi:

  • Dereferencing pointer NULL - ini adalah kasus khusus oleh perangkat keras manajemen memori
  • Mencoba mengakses alamat memori yang tidak ada (di luar ruang alamat proses)
  • Mencoba mengakses memori, program tidak memiliki hak untuk (seperti struktur kernel dalam konteks proses)
  • Mencoba menulis memori hanya baca (seperti segmen kode)

Ini pada gilirannya sering disebabkan oleh kesalahan pemrograman yang mengakibatkan akses memori tidak valid:

  • Mendereferensi atau menetapkan ke pointer yang tidak diinisialisasi (wild pointer, yang menunjuk ke alamat memori acak)

  • Dereferencing atau menetapkan ke pointer yang dibebaskan (dangling pointer, yang menunjuk ke memori yang telah dibebaskan / tidak dialokasikan / dihapus)

  • Buffer buffer.

  • Tumpukan meluap.

  • Mencoba menjalankan program yang tidak dapat dikompilasi dengan benar. (Beberapa kompiler akan menampilkan file yang dapat dieksekusi meskipun ada kesalahan waktu kompilasi.)

Roy
sumber
6

Dengan kata sederhana: segmentasi kesalahan adalah sistem operasi yang mengirimkan sinyal ke program yang mengatakan bahwa ia telah mendeteksi akses memori ilegal dan secara prematur menghentikan program untuk mencegah memori dari rusak.

FilipeCanatto
sumber
3

"Kesalahan segmentasi" berarti Anda mencoba mengakses memori yang tidak dapat Anda akses.

Masalah pertama adalah dengan argumen utama Anda. Fungsi utamanya seharusnya int main(int argc, char *argv[]), dan Anda harus memeriksa bahwa argc setidaknya 2 sebelum mengakses argv [1].

Juga, karena Anda meneruskan float ke printf (yang, dengan cara, dikonversi menjadi ganda ketika lewat ke printf), Anda harus menggunakan specifier format% f. Penentu format% s adalah untuk string (array karakter yang diakhiri '' '0).

PHP Worm ...
sumber
2

Kesalahan segmentasi atau pelanggaran akses terjadi ketika suatu program mencoba mengakses lokasi memori yang tidak ada, atau mencoba mengakses lokasi memori dengan cara yang tidak diperbolehkan.

 /* "Array out of bounds" error 
   valid indices for array foo
   are 0, 1, ... 999 */
   int foo[1000];
   for (int i = 0; i <= 1000 ; i++) 
   foo[i] = i;

Di sini saya [1000] tidak ada, jadi segfault terjadi.

Penyebab kesalahan segmentasi:

it arise primarily due to errors in use of pointers for virtual memory addressing, particularly illegal access.

De-referencing NULL pointers  this is special-cased by memory management hardware.

Attempting to access a nonexistent memory address (outside processs address space).

Attempting to access memory the program does not have rights to (such as kernel structures in process context).

Attempting to write read-only memory (such as code segment).
Mohit Rohilla
sumber
2
Pertama-tama, kesalahan seg tidak ada hubungannya dengan alamat apakah ada atau tidak. Ini tentang Anda mengaksesnya di mana Anda tidak diizinkan untuk melakukannya. Dan dalam contoh khusus Anda bahkan dijamin oleh standar bahwa lokasi itu ada. karena standar mengatakan dalam kasus array itu harus diberikan bahwa ada alamat yang valid untuk pointer pointg pada array yang disejajarkan dengan baik dalam batas-batasnya DAN 1 di belakang .
dhein
itu juga dirilis dengan alamat, jika Anda tidak memiliki alamat dan jika Anda mencoba mengakses alamat ini, juga ada seg. kesalahan. Dan dalam contoh saya, itu hanya untuk memahami sudut pandang.
Mohit Rohilla
2

Ada beberapa penjelasan yang baik tentang "kesalahan segmentasi" dalam jawaban, tetapi karena dengan segmentasi kesalahan sering ada dump dari konten memori, saya ingin berbagi di mana hubungan antara bagian "core dumped" dalam kesalahan segmentasi (core dumped) dan memori berasal dari:

Dari sekitar tahun 1955 hingga 1975 - sebelum memori semikonduktor - teknologi dominan dalam memori komputer menggunakan donat magnetik kecil yang digantung pada kabel tembaga. Donat dikenal sebagai "inti ferit" dan memori utama yang dikenal sebagai "memori inti" atau "inti".

Diambil dari sini .

Viktor Nonov
sumber
2

Ada cukup banyak definisi segmentasi kesalahan, saya ingin mengutip beberapa contoh yang saya temui saat pemrograman, yang mungkin tampak kesalahan konyol, tetapi akan menghabiskan banyak waktu.

  1. Anda bisa mendapatkan segmentasi kesalahan dalam kasus di bawah ini sementara jenis argumet tidak cocok di printf

    #include<stdio.h> int main(){
    int a = 5; printf("%s",a); return 0; }

keluaran: Segmentation Fault (SIGSEGV)

  1. ketika Anda lupa mengalokasikan memori ke pointer, tetapi mencoba menggunakannya.

     #include<stdio.h> 
     typedef struct{
       int a;
     }myStruct;   
    int main(){
      myStruct *s;
      /* few lines of code */
      s->a = 5;
      return 0;
    }

keluaran: Segmentation Fault (SIGSEGV)

NPE
sumber
1

Arti sederhana Segmentation faultadalah bahwa Anda mencoba mengakses beberapa memori yang bukan milik Anda. Segmentation faultterjadi ketika kami mencoba membaca dan / atau menulis tugas di lokasi memori hanya baca atau mencoba membebaskan memori. Dengan kata lain, kita dapat menjelaskan ini sebagai semacam korupsi memori.

Di bawah ini saya menyebutkan kesalahan umum yang dilakukan oleh programmer yang menyebabkan Segmentation fault.

  • Gunakan scanf()dengan cara yang salah (lupa menempatkan &).
int num;
scanf("%d", num);// must use &num instead of num
  • Gunakan pointer dengan cara yang salah.
int *num; 
printf("%d",*num); //*num should be correct as num only
//Unless You can use *num but you have to point this pointer to valid memory address before accessing it.
  • Memodifikasi string literal (pointer mencoba menulis atau memodifikasi memori hanya baca.)
char *str;  

//Stored in read only part of data segment
str = "GfG";      

//Problem:  trying to modify read only memory
*(str+1) = 'n';
  • Cobalah menjangkau melalui alamat yang sudah dibebaskan.
// allocating memory to num 
int* num = malloc(8); 
*num = 100; 

// de-allocated the space allocated to num 
free(num); 

// num is already freed there for it cause segmentation fault
*num = 110; 
  • Stack Overflow -: Kehabisan memori pada tumpukan
  • Mengakses array di luar batas '
  • Gunakan penentu format yang salah saat menggunakan printf()dan scanf()'
Kalana
sumber