Segmentasyon hatası nedir?


598

Segmentasyon hatası nedir? C ve C ++ 'da farklı mıdır? Segmentasyon hataları ve sarkan işaretçiler arasında nasıl bir ilişki vardır?



22
Bu durumda, neden benim durumumda derleyici hiçbir şeyden şikayet etmedi, hepsi sorunsuz gitti, ancak çalışma zamanında sistem bir segmentasyon hatası (çekirdek dökümü) atıyor? T_T
Jim Raynor

3
Bir şeyler ters gittiğinde sadece bir bellek dökümü!
Resultsway

7
@pinouchon: Komik, ama bir derleyicinin seg hatalarıyla ne zaman ilgisi var? Daha çok çalışma süresi ortamı değil mi?
dhein

1
Genellikle bir boş gösterici dereference denenerek çağrılır, bu nedenle bir segmentasyon hatası genellikle Java'ya benzer NullPointerException.
Raedwald

Yanıtlar:


673

Segmentasyon hatası, “size ait olmayan” belleğe erişmenin neden olduğu belirli bir hata türüdür. Bu, belleği bozmanızı ve hata ayıklaması zor bellek hataları getirmenizi engelleyen bir yardımcı mekanizmadır. Bir segfault aldığınızda, bellekte yanlış bir şey yaptığınızı biliyorsunuzdur - daha önce serbest bırakılmış olan değişkene erişme, belleğin salt okunur bir bölümüne yazma, vb. bellek yönetimi, C ve C ++ segfaultlar arasında temel bir fark yoktur.

En azından C (++) gibi alt düzey dillerde segfault almanın birçok yolu vardır. Segfault almanın yaygın bir yolu, boş bir göstergenin kaldırılmasıdır:

int *p = NULL;
*p = 1;

Belleğin salt okunur olarak işaretlenmiş bir bölümüne yazmaya çalıştığınızda başka bir segfault gerçekleşir:

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

İşaretçi sarkıyor, artık burada olmayan bir şeye işaret ediyor:

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

İşaretçi , blok bittikten sonra var olmayan pkarakter değişkenine işaret ettiği için sarkar c. Ve sarkan bir işaretçi (gibi *p='A') atlatmaya çalıştığınızda muhtemelen bir segfault elde edersiniz.


154
İnşa ettiğimde son örnek özellikle kötü: int main () {char * p = 0; {char c = 'x'; p = & c; } printf ("% c \ n", * p); dönüş 0; } Gcc veya diğer derleyicilerle çalışmak için 'görünür'. Derleme hakkında uyarı yok. Segfault yok. Bunun nedeni, '}' kapsam dışıdır, gerçekte verileri silmez, yalnızca tekrar kullanılabilir olarak işaretler. Kod yıllarca bir üretim sisteminde iyi çalışabilir, kodun başka bir parçasını değiştirebilir, derleyiciyi değiştirebilir veya başka bir şey yapabilir ve BOOOOOM!
Chris Huang-Leaver

36
Yumru için üzgünüm ama sadece bir yan not ... örneklerinizin hiçbiri mutlaka bir segfault'a neden olmaz, aslında sadece tanımlanmamış davranış ;-)
oldrinb

18
@oldrinb: Mutlaka bir segfault'a neden olan kod yazmak imkansızdır . En azından orada, bellek koruması olmadan çalışan sistemler olduğundan, bir bellek parçasının aslında "size ait olup olmadığını" anlayamadığı ve segfaultları bilmediği için , sadece tanımlanmamış davranış ... (klasik AmigaOS, örneğin)
DevSolar

7
@ ChrisHuang-Leaver c, bunun yerel olduğunu anlamanız gerekir , bu sonra yığın üzerine itilmiş ve sonra {dışarı pop-ed anlamına gelir }. sarkan ibre sadece yığının dışında olan bir ofset için bir referanstır. bu yüzden basit bir programda değiştirmek asla herhangi bir segfault tetiklemeyecektir. Öte yandan, daha karmaşık bir kullanım durumunda segfault'a yol açabilir, burada diğer fonksiyon çağrıları yığının büyümesine ve sarkan işaretçinin işaret ettiği verileri içermesine neden olabilir. Bu verilere yazmak (yerel varyasyonlar) tanımlanmamış davranışa (segfault & Co) yol açacaktır
Ayman Khamouma

3
@ ChrisHuang-Leaver, normalde kapsam dışında kaldığınızda, derleyici kullanılmayan yığın alanını boşaltmak için bazı yığın alanlarını kurtarmalıdır, ancak bu her zaman gerçekleşmez (gcc bu derleyicilerden biridir). Ayrıca, ayrılan yığın alanı normalde yeniden kullanılır, bu nedenle kullanılmayan yığın sayfalarını sisteme döndüren hiçbir işletim sistemi duymadım, bu alanı bir konuya SIGSEGVçevirdim, bu yüzden böyle bir sinyalin yığınla karışmasını beklemeyeceğim.
Luis Colorado

111

Segmentasyon hatasına doğrudan başka bir işlem belleğine (bazen duyduğum şey) erişmekten kaynaklanmadığını belirtmek gerekir, çünkü bu mümkün değildir. Sanal bellek ile her işlemin kendi sanal adres alanı vardır ve işaretçinin herhangi bir değerini kullanarak başka bir adrese erişmenin bir yolu yoktur. Bunun istisnası, aynı fiziksel adres alanı olan (muhtemelen) farklı sanal adreslere ve her işlemde aynı şekilde eşlenen çekirdek belleğe (syscall'da TLB'nin kızarmasını önlemek için) eşlenen paylaşımlı kütüphaneler olabilir. Ve shmat gibi şeyler;) - bunlar 'dolaylı' erişim olarak saydıklarım. Bununla birlikte, genellikle süreç kodundan çok uzakta bulunduklarını kontrol edebiliriz ve genellikle bunlara erişebiliriz (bu yüzden oradalar,

Yine de, kendi (işlem) belleğimize uygunsuz bir şekilde erişilmesi durumunda segmentasyon hatası meydana gelebilir (örneğin yazılamaz alana yazmaya çalışıyorum). Ancak bunun en yaygın nedeni, sanal adres alanının fiziksel olarak eşlenmemiş kısmına erişimdir .

Ve tüm bunlar sanal bellek sistemleri ile ilgili.


Paylaşılan bellek / bellek eşlemeli dosyalarla başka birisinin belleğinizle karıştırması mümkündür. WIN32'de 'WriteProcessMemory' gibi kötü API'ler de var!
paulm

1
@paulm: Evet, biliyorum. "Ve shmat;) gibi şeyler hakkında aklımda olan şey buydu - bunlar 'dolaylı' erişim" olarak sayıyorum.
konrad.kruczynski

Bir sanal bellek işletim sisteminde, başka bir işlem sanal belleğine erişmek için bir işlemin, normalde, bu nedenle lütfen işletim sistemi uygulayıcıları, beni alevlendirmeyin), Giriş. Sanal bellek adresleri normalde dikkate alınan işleme bağlı olarak farklı şeyler ifade eder.
Luis Colorado

38

Segmentasyon hatası, işlemin tanımlayıcı tablosunda listelemediği bir sayfa isteği veya listelediği bir sayfa için geçersiz bir istek (örneğin, salt okunur bir sayfada yazma isteği) nedeniyle oluşur.

Sarkan bir işaretçi, geçerli bir sayfayı gösterebilen veya göstermeyen, ancak "beklenmeyen" bir bellek bölümüne işaret eden bir işaretçidir.


10
Bu doğrudur, ancak bir segmentasyon hatasının ne olduğunu bilmiyorsanız gerçekten size yardımcı olur mu?
zoul

29

Dürüst olmak gerekirse, diğer posterlerin de belirttiği gibi, Wikipedia'nın bu konuda çok iyi bir makalesi var, bu yüzden oraya bir göz atın. Bu tür hatalar çok yaygındır ve genellikle Erişim İhlali veya Genel Koruma Hatası gibi başka şeyler denir.

C, C ++ veya işaretçilere izin veren başka bir dilde farklı değildirler. Bu tür hatalara genellikle

  1. Doğru şekilde başlatılmadan önce kullanılır
  2. İşaret ettikleri hafızadan sonra yeniden kullanılır veya silinir.
  3. Dizinin dizi sınırlarının dışında olduğu dizine alınmış bir dizide kullanılır. Bu genellikle yalnızca geleneksel dizilerde veya c-dizelerinde işaretçi matematiği yaparken, STL / Boost tabanlı koleksiyonlarda değil (C ++ 'da).

16

Wikipedia'ya göre:

Bir program, erişmesine izin verilmeyen bir bellek konumuna erişmeye veya bir bellek konumuna izin verilmeyen bir şekilde erişmeye çalıştığında (örneğin, salt okunur bir konuma yazmaya çalıştığında) bir bölümleme hatası oluşur veya işletim sisteminin bir kısmının üzerine yazmak için).


13

Segmentasyon hatasına ayrıca donanım arızaları, bu durumda RAM bellekleri neden olur. Bu daha az yaygın nedendir, ancak kodunuzda bir hata bulamazsanız, belki de bir memtest size yardımcı olabilir.

Bu durumda çözüm, RAM'i değiştirin.

Düzenle:

Burada bir referans var: Donanımdan bölümleme hatası


3
Hatalı RAM için hızlı ve kirli bir test, çökme programınızı bir döngüde tekrar tekrar çalıştırmaktır. Programda dahili bir belirsizliği yoksa - yani, aynı girdi için her zaman aynı çıktıyı üretir veya en azından öyle olması gerekir - ancak, belirli bir girdi için, bazen her zaman değil ama asla değil: kötü RAM için endişelenmeye başlayın.
zwol

8

Segmentasyon hatası , bir işlem (bir programın çalışan örneği) başka bir işlem tarafından kullanılan veya var olmayan (geçersiz) bellek adresine erişen salt okunur bellek adresine veya bellek aralığına erişmeye çalıştığında oluşur. Sarkan Referans (işaretçi) sorunu , içeriği bellekten zaten silinmiş olan bir nesneye veya değişkene erişmeye çalışmanın, örneğin:

int *arr = new int[20];
delete arr;
cout<<arr[1];  //dangling problem occurs here

4
Bir diziyi silmenin doğru yolu delete [] arr;
Damian

8

Wikipedia'nın Segmentation_fault sayfası, bunun nedenlerini ve nedenlerini işaret ederek çok güzel bir açıklamaya sahiptir. Ayrıntılı bir açıklama için wiki'ye bir göz atın.

Hesaplamada, bir segmentasyon hatası (genellikle segfault'a kısaltılır) veya erişim ihlali, bellek korumalı bir donanım tarafından oluşturulan ve işletim sistemini (OS) bellek erişim ihlali hakkında bilgilendiren bir hatadır.

Bir segmentasyon hatasının tipik nedenleri şunlardır:

  • NULL işaretçileri silme - bu, bellek yönetimi donanımı tarafından özel olarak kullanılır
  • Var olmayan bir bellek adresine erişmeye çalışmak (işlemin adres alanının dışında)
  • Belleğe erişmeye çalışmak programın haklarına sahip değildir (süreç bağlamındaki çekirdek yapıları gibi)
  • Salt okunur bellek yazmaya çalışma (kod segmenti gibi)

Bunlara genellikle geçersiz bellek erişimi ile sonuçlanan programlama hataları neden olur:

  • Başlatılmamış bir işaretçiyi silme veya atama (rasgele bellek adresini gösteren vahşi işaretçi)

  • Serbest bırakılmış bir işaretçiyi silme veya atama (serbest bırakılmış / serbest bırakılmış / silinmiş belleğe işaret eden sarkan işaretçi)

  • Bir arabellek taşması.

  • Bir yığın taşması.

  • Doğru derlenmeyen bir program yürütülmeye çalışılıyor. (Bazı derleyiciler, derleme zamanı hatalarına rağmen yürütülebilir bir dosya çıkarır.)


6

Basit bir ifadeyle: segmentasyon hatası, programa, programa bir sinyal erişimi göndererek geçersiz bellek erişimi algıladığını ve belleğin bozulmasını önlemek için programı erken sonlandırdığını söyler.


3

"Segmentasyon hatası", erişiminiz olmayan belleğe erişmeye çalıştığınız anlamına gelir.

İlk sorun ana argümanlarınızdır. Ana işlev olmalıdır int main(int argc, char *argv[])ve argv [1] 'e erişmeden önce argc öğesinin en az 2 olduğunu kontrol etmelisiniz.

Ayrıca, printf'e bir float geçirdiğinizden (bu arada, printf'e geçerken bir çifte dönüştürülür),% f format belirleyicisini kullanmalısınız. % S biçim belirteci dizeler içindir ('\ 0' sonlandırılmış karakter dizileri).


2

Bir program var olmayan bir bellek konumuna erişmeye veya bir bellek konumuna izin verilmeyen bir şekilde erişmeye çalıştığında bir segmentasyon hatası veya erişim ihlali oluşuyor.

 /* "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;

Burada i [1000] mevcut değil, bu yüzden segfault oluşur.

Segmentasyon hatasının nedenleri:

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).

2
Her şeyden önce, seg hatasının adresin var ya da yok ile ilgisi yoktur. Bu, izin verilmeyen bir yere eriştiğinizle ilgilidir. Ve özel örneğinizde, bu yerin var olması standart olarak garanti edilir. standart dizi durumunda söylediği için, arkasındaki AND 1 içindeki iyi hizalanmış bir dizide bir işaretçi pointg için geçerli bir adres olması gerektiği belirtilmelidir .
dhein

adresle de ilgilidir, eğer adresiniz yoksa ve bu adrese erişmeye çalışırsanız seg da vardır. arıza. Ve örneğimde, bu sadece bakış açısını anlamak içindir.
Mohit Rohilla

2

Yanıtlarda "Segmentasyon hatası" nın birkaç iyi açıklaması vardır, ancak segmentasyon hatası ile genellikle bellek içeriğinin bir dökümü olduğundan, Segmentasyon hatası (çekirdek dökümü) içindeki "çekirdek dökümü" kısmı arasındaki ilişkinin ve bellek:

Yaklaşık 1955'ten 1975'e kadar - yarıiletken belleğinden önce - bilgisayar belleğindeki baskın teknoloji, bakır tellere asılmış küçük manyetik çörekleri kullandı. Donutlar "ferrit çekirdekler" ve "çekirdek bellek" veya "çekirdek" olarak bilinen ana bellek olarak biliniyordu.

Buradan alındı .


2

Segmentasyon hatası yeterli tanımları vardır, ben programlama sırasında karşılaştığım, aptalca hatalar görünebilir, ancak çok zaman harcayacak birkaç örnek alıntı istiyorum.

  1. printf'de argumet tipi uyuşmazlığı varken aşağıdaki durumda segmentasyon hatası alabilirsiniz

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

çıktı : Segmentation Fault (SIGSEGV)

  1. bir işaretçiye bellek ayırmayı unuttuğunuzda, ancak kullanmaya çalıştığınızda.

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

çıktı : Segmentation Fault (SIGSEGV)


1

Basit anlamı, Segmentation faultsize ait olmayan bir hafızaya erişmeye çalışmanızdır. Segmentation faultgörevleri salt okunur bir bellek konumunda okumaya ve / veya yazmaya çalıştığımızda veya belleği boşaltmaya çalıştığımızda oluşur. Başka bir deyişle, bunu bir çeşit bellek bozulması olarak açıklayabiliriz.

Aşağıda programcıların yol açtığı yaygın hatalardan bahsediyorum Segmentation fault.

  • scanf()Yanlış şekilde kullanın (koymayı unuttum &).
int num;
scanf("%d", num);// must use &num instead of num
  • İşaretçileri yanlış şekilde kullanın.
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.
  • Bir dizgi değişmezini değiştirme (işaretçi salt okunur bir belleği yazmaya veya değiştirmeye çalışır.)
char *str;  

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

//Problem:  trying to modify read only memory
*(str+1) = 'n';
  • Zaten serbest bırakılmış bir adres üzerinden ulaşmaya çalışın.
// 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; 
  • Yığın Taşması -: Yığındaki bellek yetersiz
  • Bir diziye sınırların dışında erişiliyor '
  • Kullanırken yanlış format belirteçleri kullanın printf()ve scanf()'
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.