Segmentasyon Hatası, başlık altında nasıl çalışır?


266

Bununla ilgili herhangi bir bilgiyi "İşlemcinin MMU'su bir sinyal gönderir" ve "çekirdek, onu suçlu programa yönlendirir, onu sonlandırır" demiştir.

Büyük olasılıkla sinyali kabuğa gönderdiğini ve kabuğun, rahatsız edici işlemi ve baskı işlemini sonlandırmak suretiyle gerçekleştirdiğini varsaydım "Segmentation fault". Ben de bu varsayımı, crsh (bok kabuğu) diye adlandırdığım oldukça az miktarda bir kabuk yazarak test ettim . Bu kabuk kullanıcı girişi almak ve system()yöntemi beslemek dışında hiçbir şey yapmaz .

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

int main(){
    char cmdbuf[1000];
    while (1){
        printf("Crap Shell> ");
        fgets(cmdbuf, 1000, stdin);
        system(cmdbuf);
    }
}

Ben de bu kabuğu çıplak bir terminalde ( bashaltından geçmeden ) koştum . Sonra bir segfault üreten bir program çalıştırmaya başladım. Varsayımlarım doğru olsaydı, bu bir a) çarpışmak crsh, xterm'i kapatmak, b) yazdırmamak "Segmentation fault"ya da c) ikisini birden yapmaktı.

braden@system ~/code/crsh/ $ xterm -e ./crsh
Crap Shell> ./segfault
Segmentation fault
Crap Shell> [still running]

Birinci kareye geri döndüm sanırım. Daha önce bunu yapan kabuğun değil, altındaki sistemin olduğunu gösterdim. "Bölümlendirme hatası" nasıl yazdırılıyor? "Kim" yapıyor? Çekirdek mi? Başka bir şey? Sinyal ve tüm yan etkileri donanımdan programın sonlandırılmasına nasıl yayılır?


43
crshBu tür deneyler için harika bir fikir. Hepimizi ve arkasındaki fikri bize bildirdiğiniz için teşekkür ederiz.
Bruce Ediger,

30
İlk gördüğümde crsh, "çarpışma" olarak telaffuz edileceğini düşündüm. Bunun eşit derecede uygun bir isim olup olmadığından emin değilim.
jpmc26

56
Bu güzel bir deney ... ama system()kaputun altında ne olduğunu bilmelisin . system()Kabuklu bir sürecin ortaya çıkacağı ortaya çıktı ! Bu nedenle, kabuk işleminiz başka bir kabuk işleminde ortaya çıkar ve bu kabuk işlemi (muhtemelen /bin/shveya bunun gibi bir şey) programı çalıştıran işlemdir . Yol /bin/shveya bashçalışma, fork()ve exec()(veya execve()ailedeki başka bir işlevi ) kullanmaktır.
Dietrich Epp

4
@BradenBest: Kesinlikle. Kılavuz sayfasını okuyun, man 2 waitmakrolar WIFSIGNALED()ve içerecektir WTERMSIG().
Dietrich Epp

4
@DietrichEpp Aynen dediğiniz gibi! (WIFSIGNALED(status) && WTERMSIG(status) == 11)Goofy ( "YOU DUN GOOFED AND TRIGGERED A SEGFAULT") bir şey yazdırmak için bir çek eklemeye çalıştım . segfaultProgramı içeriden çalıştırdığımda, crshtam olarak bunu basıyordu. Bu arada, normal olarak çıkan komutlar hata mesajı vermez.
Braden Best

Yanıtlar:


248

Tüm modern CPU'lar şu anda çalışmakta olan makine talimatlarını kesme kapasitesine sahiptir . Daha sonra hiçbir şey olmamış gibi yürütmeyi devam ettirmek için yeterli durumda (genellikle, ancak her zaman değil, yığında) tasarruf ederler (kesilen komut genellikle sıfırdan yeniden başlatılır). Ardından , daha fazla makine kodu olan ancak özel bir yere yerleştirilen bir kesme eylemcisi çalıştırmaya başlarlar ; böylece CPU önceden nerede olduğunu bilir. Kesme işleyicileri her zaman işletim sisteminin çekirdeğinin bir parçasıdır : en büyük ayrıcalıkla çalışan ve diğer tüm bileşenlerin yürütülmesini denetlemekten sorumlu olan bileşen. 1,2

Kesintiler eşzamanlı olabilir ; bu, işlemcinin kendisi tarafından tetiklenen, şu anda yürütülen talimatın yaptığı bir şeye doğrudan yanıt olarak veya eşzamansız olarak, ağa gelen veriler gibi harici bir olay nedeniyle öngörülemeyen bir zamanda gerçekleştiği anlamına gelir. Liman. Bazı insanlar eşzamansız kesintiler için "kesme" terimini saklar ve bunun yerine eşzamanlı kesintileri "tuzaklar", "hatalar" veya "istisnalar" olarak adlandırır, ancak bu kelimelerin hepsinin başka anlamları vardır, bu yüzden "eşzamanlı kesintiye" bağlı kalacağım.

Şimdi, çoğu modern işletim sistemi bir süreç kavramına sahiptir . En temelde, bu, bilgisayarın aynı anda birden fazla programı çalıştırabileceği bir mekanizmadır, ancak aynı zamanda işletim sistemlerinin en çok bir özellik olan bellek korumasını nasıl yapılandırdığının da önemli bir özelliğidir (fakat, ne yazık ki, hala hepsi değil ) modern işlemciler. Sanal bellek ile birlikte gidiyorbellek adresleri ve RAM'deki gerçek konumlar arasındaki eşlemeyi değiştirme yeteneğidir. Bellek koruması, işletim sisteminin her bir işleme kendi özel RAM yığınını vermesini, yalnızca erişebilmesini sağlar. Ayrıca, işletim sisteminin (bazı işlemler adına hareket ederek) RAM bölgelerini salt okunur, çalıştırılabilir, bir grup işbirliği işlemiyle paylaşılan, vb. Olarak belirlemesine olanak tanır. çekirdek. 3

Her işlem belleğe yalnızca CPU'nun izin verecek şekilde yapılandırıldığı şekilde eriştiği sürece, bellek koruması görünmezdir. Bir işlem kuralları çiğnediğinde, CPU çekirdeği işleri çözmesini isteyen bir eşzamanlı kesmeye neden olur. Sürecin kuralları gerçekten ihlal etmediği düzenli olarak gerçekleşir, işlemin devam etmesine izin verilmeden önce sadece çekirdeğin biraz çalışması gerekir. Örneğin, bir işlem belleğinin bir sayfasının RAM'de başka bir şey için yer açmak için takas dosyasına "çıkarılması" gerekirse, çekirdek bu sayfaya erişilemez olarak işaretler. İşlem bir daha kullanmaya çalıştığında, CPU bir bellek koruma kesmesi üretecektir; çekirdek, sayfayı takastan alır, bulunduğu yere geri koyar, tekrar erişilebilir olarak işaretler ve yürütmeye devam eder.

Ancak, sürecin gerçekten kuralları ihlal ettiğini varsayalım. Daha önce hiç RAM eşleştirilmemiş bir sayfaya erişmeye çalıştı ya da makine kodu içermeyen olarak işaretlenmiş bir sayfa veya herhangi bir şekilde çalıştırmaya çalıştı. Genellikle "Unix" olarak bilinen işletim sistemleri ailesinin tümü , bu durumla başa çıkmak için sinyaller kullanır. 4 Sinyaller kesintilere benzer, ancak bunlar donanım tarafından üretilmek ve çekirdeğin alanından ziyade çekirdek tarafından üretilir ve alanlara göre alanlandırılır. İşlemler sinyal işleyicileri tanımlayabilirkendi kodlarında ve çekirdeğe nerede olduklarını söyleyin. Bu sinyal işleyicileri daha sonra gerektiğinde normal kontrol akışını keserek yürütecektir. Sinyallerin hepsinde, biri şifreli bir kısaltma ve diğeri biraz daha az şifreli bir cümle olan bir sayı ve iki isim vardır. Bir işlem bellek koruma kurallarını ihlal ettiğinde üretilen sinyal (kurallara göre) 11 numaradır ve isimleri SIGSEGVve "Segmentasyon hatası" dır . 5,6

Sinyaller ve kesintiler arasındaki önemli bir fark , her sinyal için varsayılan bir davranış olduğudur. İşletim sistemi tüm kesintiler için işleyiciler tanımlayamazsa, bu işletim sisteminde bir hatadır ve CPU eksik bir işleyici çağırmaya çalıştığında tüm bilgisayar çökecektir. Ancak, işlemler tüm sinyaller için sinyal işleyicileri tanımlama zorunluluğu yoktur. Eğer çekirdek bir işlem için bir sinyal üretirse ve bu sinyal varsayılan davranışında bırakılmışsa, çekirdek devam eder ve varsayılanı ne olursa olsun ve işlemi rahatsız etmez. Çoğu sinyalin varsayılan davranışları ya "hiçbir şey yapmaz" ya da "bu süreci sonlandırır ve belki de bir çekirdek dökümü üretir" dir. SIGSEGVikincisi biridir.

Yani, özetlemek için, hafıza koruma kurallarını ihlal eden bir süreç var. CPU süreci askıya aldı ve senkronize bir kesinti oluşturdu. Çekirdek, kesilen ve SIGSEGVişlem için bir sinyal üreten alan oluşturdu . En vermedi sürecini varsayalım değil bir sinyal işleyici kurmak SIGSEGV, böylece çekirdek işlemini sonlandırmak için varsayılan davranışı, gerçekleştirmektedir. Bu, _exitsistem çağrısıyla aynı etkilere sahiptir : açık dosyalar kapalı, hafızanın silinmesi vb.

Bu noktaya kadar hiçbir şey bir insanın görebileceği herhangi bir mesaj yayınlamadı ve kabuk (ya da daha genel olarak, yeni sona eren sürecin ana süreci ) hiç yer almadı. SIGSEGVkuralları ihlal eden sürece gider , ebeveyni değil . Ancak , dizideki bir sonraki adım, çocuğunun sonlandırıldığı ana işlemi bildirmek. Bu ebeveyn zaten birini kullanarak, bu bildirim için bekleyen olduğunda en basit olduğu birkaç farklı şekilde gerçekleşebilir waitsistem çağrıları ( wait, waitpid, wait4, vs). Bu durumda, çekirdek yalnızca bu sistem çağrısının geri dönmesine neden olur ve ana işlemi çıkış durumu adı verilen bir kod numarası ile sağlar.. 7 Çıkış durumu ebeveyne çocuk sürecinin neden sona erdirildiği bilgisini verir; Bu durumda, bir SIGSEGVsinyalin varsayılan davranışı nedeniyle çocuğun sonlandırıldığını öğrenecektir .

Ana işlem daha sonra bir mesajı yazdırarak olayı bir insana rapor edebilir; Shell programları neredeyse her zaman bunu yapıyor. Sizin crshbunu kodunu içermiyorsa, ancak C kütüphanesi rutin çünkü, zaten olur systemtam özellikli kabuk çalıştırır /bin/sh"kaputun altındaki". bu senaryoda büyükbabacrsh veya büyükbaba ; ana-işlem bildirimi, /bin/shnormal mesajını basan alan alanına yazılır . Daha sonra /bin/sh, yapacak başka bir şeyi olmadığından ve C kütüphanesinin bu çıkış bildirimini systemaldığı için kendiliğinden çıkar . Bu çıkış bildirimini kodunuzun, dönüş değerini inceleyerek görebilirsiniz.system; fakat size torun sürecinin bir sicil suçunda öldüğünü söylemez, çünkü bu ara kabuk işlemi tarafından tüketildi.


Dipnotlar

  1. Bazı işletim sistemleri, aygıt sürücülerini çekirdeğin bir parçası olarak kullanmaz; Ancak bütün kesme işleyicileri hala çekirdeğin bir parçası olmak zorunda ve donanım şey izin vermediğinden bu yüzden, bellek koruması yapılandıran kod yapar ama bunları yapmak için çekirdekte.

  2. Çekirdekten daha ayrıcalıklı bir "hiper yönetici" veya "sanal makine yöneticisi" olarak adlandırılan bir program olabilir, ancak bu cevabın amaçları için donanımın bir parçası olarak kabul edilebilir .

  3. Çekirdek bir programdır , ancak bir süreç değildir ; daha çok bir kütüphane gibi. Tüm işlemler kendi kodlarına ek olarak zaman zaman çekirdek kodunun bazı bölümlerini yürütür. Yalnızca çekirdek kodunu çalıştıran bir dizi "çekirdek ipliği" olabilir , ancak burada bizi ilgilendirmez.

  4. Artık , Unix'in bir uygulaması olarak kabul edilemeyecek olan ve artık uğraşmanız gereken tek işletim sistemi Windows'tur. Bu durumda sinyal kullanmaz. (Gerçekten de, yok olması ; Windows üzerinde sinyalleri <signal.h>It "denen birşey kullanan arayüz tamamen C kütüphanesi tarafından sahte olduğu.) Yapılandırılmış istisna işleme yerine".

  5. Bazı bellek koruma ihlalleri, SIGBUSbunun yerine ("Veriyolu hatası") üretir SIGSEGV. İkisi arasındaki çizgi belirlenir ve sistemden sisteme değişir. Bir işleyiciyi tanımlayan bir program SIGSEGVyazdıysanız, aynı işleyiciyi tanımlamak iyi bir fikir olabilir SIGBUS.

  6. "Bölümlendirme hatası", orijinal Unix’i , muhtemelen de PDP-11’i çalıştıran bilgisayarlardan birinin hafıza koruması ihlalleri için oluşturduğu kesintinin adıydı . " Segmentasyon " bir tür hafıza korumasıdır, ancak günümüzde "segmentasyon hatası " terimi genel olarak herhangi bir tür hafıza koruma ihlali anlamına gelir.

  7. Bütün diğer ebeveyn süreç bir çocuğun bildirim alabilirsiniz yolları ebeveyn çağrı ile bitirmek, sona sahip waitve çıkış durumları alma. Sadece ilk önce başka bir şey olur.


@ zvol: ad 2) İşlemcinin işlemler hakkında bir şey bildiğini söylemenin doğru olduğunu sanmıyorum. Söylemelisin ki, kontrolü transfer eden bir kesme eylemcisi.
user323094

9
@ user323094 Modern çok çekirdekli işlemciler aslında işlemler hakkında oldukça az şey biliyor; bu durumda, yalnızca bellek koruma hatasını tetikleyen yürütme iş parçacığını askıya alabilirler. Ayrıca, düşük seviyeli ayrıntılara girmemeye çalışıyordum. Kullanıcı alanı programcısının bakış açısından, 2. adımda anlaşılması gereken en önemli şey , hafıza koruma ihlallerini tespit eden donanım olmasıdır; daha az bu yüzden “suç işleyen süreci” belirleme konusunda donanım, donanım yazılımı ve işletim sistemi arasındaki kesin iş bölümü.
zwol

Saf bir okuyucunun kafasını karıştırabilecek başka bir incelik "Çekirdek rahatsız edici işlemi bir SIGSEGV sinyali gönderir" şeklindedir. hangi zamanki jargon kullanan, ama aslında çekirdek söyler demektir kendisini (yüklü bir sinyal işleyici, çekirdek tarafından çözümlenir bir soru olmadığı sürece userland kodu yer almak değil yani) işlem çubuğunda sinyal foo başa. Bazen bu nedenle "süreçte bir SIGSEGV sinyalini yükseltmeyi" tercih ediyorum .
dmckee

2
SIGBUS (veriyolu hatası) ve SIGSEGV (segmentasyon hatası) arasındaki önemli fark şudur: SIGSEGV, CPU bir adrese erişmemeniz gerektiğini bildiğinde oluşur (ve bu nedenle herhangi bir harici bellek veri yolu isteği yapmaz). SIGBUS, CPU sadece adresleme problemini öğrendiğinde isteğinizi dış adres veriyoluna ilettiğinde ortaya çıkar. Örneğin, otobüste hiçbir şeyin yanıt vermeyeceği bir fiziksel adres sormak veya yanlış hizalanmış bir sınırla ilgili verileri okumak istemek (bunun yerine iki fiziksel istek olmasını gerektirir)
Stuart Caie

2
@StuartCaie Kesintilerin davranışını açıklıyorsunuz ; Gerçekten de, çoğu CPU, sizin belirlediğiniz ayrımı yapar (bazıları olmasa da ikisi arasındaki çizgi değişir). Sinyalleri SIGSEGV ve SIGBUS Ancak edilir değil güvenilir bu iki işlemci düzey koşulları çizilmiştir. POSIX’in SIGSEGV yerine SIGBUS istediği tek koşul mmap, dosyadan daha büyük bir bellek bölgesine dosya yazıp ardından dosyanın sonuna kadar "tam sayfalara" erişmenizdir. (POSIX, SIGSEGV / SIGBUS / SIGILL / etc'nin ne zaman gerçekleştiği konusunda oldukça belirsizdir.)
zwol

42

Kabuğun gerçekten de bu mesajla ilgisi var ve crshdolaylı olarak muhtemelen bir kabuk çağırıyor bash.

Her zaman hataları kesen küçük bir C programı yazdım:

#include <stdio.h>

int
main(int ac, char **av)
{
        int *i = NULL;

        *i = 12;

        return 0;
}

Varsayılan kabuğumdan çalıştırdığımda şunu alıyorum zsh:

4 % ./segv
zsh: 13512 segmentation fault  ./segv

Onu gelen çalıştırdığınızda bash, ben size söz kaydetti olsun:

bediger@flq123:csrc % ./segv
Segmentation fault

Benim kodunda bir sinyal işleyici yazacaktım, sonra ben fark system()kullandığı kütüphane çağrı crshexec, bir kabuk var /bin/shgöre man 3 system. Bu /bin/shkesinlikle kesinlikle "Segmentasyon hatası" yazıyor, çünkü crshkesinlikle değil.

Programı çalıştırmak crshiçin execve()sistem çağrısını kullanmak üzere yeniden yazarsanız , "Bölümlendirme hatası" dizesini görmezsiniz. Tarafından çağrılan kabuktan geliyor system().


5
Bunu sadece Dietrich Epp ile tartışıyordum. Ben araya kesmek kullanan crsh bir sürümünü execvp, bu yok ve kabuk hala çökmez ise (yani SIGSEGV kabuk hiçbir zaman gönderilmez) bulmak için tekrar test yaptım değil "Segmentasyon hatasına" yazdırmak. Hiçbir şey yazdırılmaz. Bu, kabuğun çocuk süreçlerinin ne zaman öldürüldüğünü algıladığını ve “Segmentasyon hatası” nın (veya bunun bir türevinin) basılmasından sorumlu olduğunu gösteriyor gibi görünmektedir.
Braden Best

2
@BradenBest - Aynı şeyi yaptım, benim kodum sizin kodunuzdan daha sade. Hiç mesajım yok ve hatta crappier kabuğum bile bir şey basmıyor. waitpid()Her çatalı / exec'i kullandım ve segmentasyon hatası olan işlemler için, 0 durumundan çıkan işlemlerden farklı bir değer döndürür.
Bruce Ediger,

21

Bununla ilgili herhangi bir bilgiyi "İşlemcinin MMU'su bir sinyal gönderir" ve "çekirdek, onu suçlu programa yönlendirir, onu sonlandırır" demiştir.

Bu biraz bozuk bir özet. Unix sinyal mekanizması, süreci başlatan CPU'ya özgü olaylardan tamamen farklıdır.

Genel olarak, kötü bir adrese erişildiğinde (veya salt okunur bir alana yazılırsa, çalıştırılamayan bir bölümü yürütmeye çalışın, vb.), CPU bazı işlemciye özgü bir olay üretecektir (geleneksel VM olmayan mimarilerde bu bölümleme ihlali olarak adlandırılır, çünkü her "bölüm" (geleneksel olarak salt okunur çalıştırılabilir "metin", yazılabilir ve değişken uzunluklu "veri" ve geleneksel olarak belleğin zıt ucundaki yığın) sabit bir adres aralığına sahip olduğundan Modern bir mimaride, bir sayfa hatası [eşlenmemiş bellek için] veya erişim ihlali [okuma, yazma ve izin sorunları için] ve daha fazlası için buna odaklanmam daha olasıdır.

Şimdi, bu noktada, çekirdek birkaç şey yapabilir. Sayfa hataları aynı zamanda geçerli ancak yüklenmemiş (örneğin değiştirilmiş veya mmapped bir dosyada vb.) Bellek için de üretilir ve bu durumda çekirdek belleği eşler ve kullanıcı programını yeniden başlatan komuttan yeniden başlatır. hata. Aksi takdirde, bir sinyal gönderir. Bu, tam olarak "orijinal olayı], rahatsız edici programa yönlendirmez", çünkü bir sinyal işleyicisini kurma işlemi, programın bir kesme işleyicisi kurulmasını taklit etmeyi umuyorsa, farklı ve çoğunlukla mimariden bağımsızdır.

Kullanıcı programında bir sinyal işleyici kuruluysa, bu bir yığın çerçeve oluşturmak ve kullanıcı programının yürütme konumunu sinyal işleyiciye ayarlamak anlamına gelir. Aynısı tüm sinyaller için yapılır, ancak bir segmentasyon ihlali durumunda, işler genellikle sinyal işleyicisinin geri dönmesi durumunda hataya neden olan talimatı yeniden başlatacak şekilde düzenlenir. Kullanıcı programı hatayı gidermiş olabilir, örneğin hafızayı kesin adrese eşleyerek - bunun mümkün olup olmamasına bağlı olarak mimariye bağlıdır). Sinyal işleyicisi ayrıca , kötü bellek erişimine neden olan herhangi bir işlemi iptal etmek için programda farklı bir yere de atlayabilir (tipik olarak longjmp yoluyla veya bir istisna atarak).

Kullanıcı programında bir sinyal işleyici kurulmamışsa, basitçe sonlandırılır. Bazı yapılarda, sinyal göz ardı edilirse, talimatı tekrar tekrar başlatabilir ve sonsuz bir döngüye neden olabilir.


+1, yalnızca kabul edilene bir şey ekleyen yanıt. "Segmentasyon" tarihinin güzel açıklaması. Eğlenceli bir gerçek: x86 aslında hala vardır segmenti sınırlarını , hafıza üretebilir erişmek talimatlar böylece (veya çağrı (sanal bellek) etkin olmayan) 32 bit korumalı modda #PF(fault-code)(sayfa hatası) veya #GP(0)( "Bir bellek işlenen etkin adres CS dışındaysa, DS, ES, FS veya GS segment sınırı. "). 64bit modu, segment limit kontrollerini düşürür, çünkü işletim sistemleri sadece bunun yerine disk belleği kullanır ve kullanıcı alanı için düz bellek modeli kullanır.
Peter Cordes

Aslında, x86'daki işletim sistemlerinin çoğunun bölümlenmiş sayfalama kullandığına inanıyorum: düz, sayfalanmış bir adres alanı içinde bir sürü büyük bölüm. Her bir adres alanına çekirdek hafızasını böyle korur ve
eşlersiniz

Ayrıca, NT'de (ancak çoğu Unix'te aynı olup olmadığını bilmek isterdim!) "Segmentasyon hatası" oldukça sık meydana gelebilir: kullanıcı alanının başında 64k korumalı bir bölüm var, bu nedenle NULL göstergesinin kaldırılması bir (uygun?) segmentasyon hatası
Lorenzo Dematté

1
@ LorenzoDematté Evet, tamamen ya da neredeyse hepsi modern Unixes, NULL başvuruları yakalamak için adres alanının başlangıcında kalıcı olarak eşlenmemiş adresler bir yığın bırakacak. 64 bit sistemlerde oldukça büyük olabilir, aslında dört gigabayt olabilir , böylece işaretçilerin yanlışlıkla 32 bite kesilmesi derhal yakalanır. Bununla birlikte, katı x86 anlamında segmentasyon neredeyse hiç kullanılmıyor; kullanıcı alanı için bir tane ve çekirdek için bir tane, FS ve GS'den biraz faydalanmak gibi özel numaralar için bir çift vardır.
zwol,

1
@ LorenzoDematté NT sinyal yerine istisnalar kullanır; bu durumda STATUS_ACCESS_VIOLATION.
Random832,

18

Bir segmentasyon hatası, izin verilmeyen bir hafıza adresine bir erişimdir (işlemin bir parçası değil veya salt okunur veri yazmaya veya çalıştırılamayan verileri yürütmeye çalışarak ...). Bu, MMU (bugün CPU'nun bir parçası olan Bellek Yönetimi Birimi) tarafından kesintiye neden olarak tutuluyor. Kesinti, rahatsız edici sürece bir SIGSEGFAULTsinyal ( signal(2)örneğin bakınız ) gönderen çekirdek tarafından gerçekleştirilir . Bu sinyal için varsayılan işleyici çekirdeği döker (bkz core(5)) ve işlemi sonlandırır.

Kabuğun bu konuda kesinlikle eli yok.


3
Yani C kütüphaneniz, Masaüstündeki glibc gibi , dizgiyi mi tanımlar?
drewbenn

7
Ayrıca, SIGSEGV'nin ele alınabileceğini / göz ardı edilebileceğini de belirtmek gerekir. Böylece, sonlandırılmayan bir program yazmak mümkündür. Java Sanal Makinesi, burada belirtildiği gibi, SIGSEGV'i farklı amaçlar için dahili olarak kullanan önemli bir örnektir: stackoverflow.com/questions/3731784/…
Karol Nowak,

2
Benzer şekilde, Windows'ta .NET çoğu durumda boş işaretçi kontrolleri eklemeyi zahmet etmiyor - yalnızca erişim ihlallerini yakalar (segfaults'ye eşdeğer).
immibis
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.