Segmentation fault hatam nereye kayboldu?
(rmpr.xyz)entrile bir C programını tekrar tekrar derleyip çalıştırıncahelloanormal biçimde sonlandı, ancak derleme çıktısından sonraSegmentation faultmesajı görünmedi- Bu mesajı çöken program değil, alt süreci toplarken
SIGSEGVile sonlandığını gören üst kabuk yazdırır bash -caçıkça belirtilse bile geriye kalan komut fiilen tek bir komutsa Bash yeni bir süreç oluşturmadanexecveile kendini değiştirebilir; bu yüzden mesajı yazdıracak üst kabuk ortadan kaybolur- Ayrı bir betikte ise shebang ile başlatılan Bash,
./helloyu alt süreç olarak çalıştırıp beklediği içinSIGSEGVi görür veSegmentation fault (core dumped)çıktısını verir ./helloyu alt kabukta(./hello)çalıştırmak veya arkasına; trueekleyerek sonraki işi bırakmak,execoptimizasyonunu engelleyip hata mesajını görmeyi sağlar
Mesajın kaybolduğu çalıştırma yolu
-
Aşağıdaki
entrkomutuylahello.cher değiştiğinde derleme ve çalıştırma tekrarlanırls hello.c | entr -s "gcc -o hello hello.c && ./hello" -
hellosegmentation fault ile sonlandı, ancakSegmentation faultmesajı ya da gözle görülür sıfır olmayan bir çıkış durumu olmadan hiçbir çıktı bırakmadı -
Komutu
bash -cile sarmalayınca da sonuç aynıydıls hello.c | entr -s "bash -c 'gcc -o hello hello.c && ./hello'" -
Buna karşılık aynı komut
run.shiçine taşınıp çalıştırıldığında hata gösterilir#!/bin/bash gcc -o hello hello.c && ./hellols hello.c | entr -s ./run.sh ./run.sh: line 2: 104465 Segmentation fault (core dumped) ./hello -
Segmentation faultçıktısını veren taraf- Çöken program zaten sonlanmış durumdadır; üst kabuk alt süreci toplarken
SIGSEGVile öldüğünü anladıktan sonra mesajı yazdırır - Bu nedenle mesajı yazdıracak bir üst kabuk kalmamışsa hiçbir şey görünmez
- Bash,
bash -c "some_command"içinde yapılacak iş fiilen yalnızca o komutsa yeni süreç fork etmedenexecveile kendini değiştirebilir - Bu optimizasyon çoğu çalıştırmada dışarıdan fark edilmez
- Betik yönteminde
entr,./run.shyi alt süreç olarak çalıştırır ve shebang yeni bir Bash başlatır - Yeni Bash,
gccçalıştıktan sonra./helloyu fork edip beklediği için alt sürecinSIGSEGVile sonlandığını görerek hata mesajı bırakabilir
- Çöken program zaten sonlanmış durumdadır; üst kabuk alt süreci toplarken
Üst kabuğu elde tutmanın iki yolu
- Çöken komut alt kabukta çalıştırılırsa mesaj yeniden görünür
ls hello.c | entr -s "gcc -o hello hello.c && (./hello)" hello.c: line 1: 106595 Segmentation fault (core dumped) ( ./hello )- Parantezler
./hellonun fork edilen bir alt kabukta çalıştırılmasını zorunlu kılar - Bash üst süreç rolünü koruduğundan alt kabuğun
SIGSEGVile sonlanmasını toplayıp mesajı yazdırabilir
- Parantezler
- Çöken komuttan sonra çalıştırılacak bir iş bırakmak da
execoptimizasyonunu engelleyebilirls hello.c | entr -s "bash -c 'gcc -o hello hello.c && ./hello; true'" bash: line 1: 109516 Segmentation fault (core dumped) ./hello; truenedeniyle Bash,./hellobittikten sonra da yapacak işi kaldığı için kendini o programla değiştirmez- Ayrı bir sarmalayıcı betik olmadan da segmentation fault mesajı görülebilir
1 yorum
Lobste.rs yorumları
Güncel Linux dağıtımları varsayılan olarak core dump’ları devre dışı bıraktığı için çoğu zaman sıkıntı çıkıyor
ulimit -c unlimitedile yeniden etkinleştirilebiliyor, ancak core dosyası çalıştırılabilir dosyayla aynı dizinde de oluşmuyor gibi; systemd onu bir yerlere taşıyor gibi görünüyorOpenBSD’deki gibi core dump’ların varsayılan olarak etkin olup çalıştırılabilir dosyayla aynı dizine konması iyi olurdu; şu anda bir çökme olduğunda genellikle çalıştırılabilir dosyayı gdb içinde yeniden çalıştırmak gerekiyor
coredumpctlkullanılabiliyor/usr/bingibi yerlerde core dump aramayı düşünmem bile; üstelik bu tür konumlar çoğu zaman kapasitesi küçük ya da salt okunur dosya sistemlerinde bulunuyorVarsayılan konum olarak çalışma dizini çok daha iyi olmaz mı?
Hatta kullanıcı core dosyalarını etkinleştirse bile ne yaptığını bilmediği varsayılıyor; bu yüzden dosyalar root’un bile bulmakta zorlanacağı bir yere saklanıyormuş gibi hissettiriyor
C veya D gibi dillerle program yazarken çıkış nedenini bilmek istiyorsanız
waitsistem çağrısının dönüş değerini kontrol edebilirsiniz; programın bir sinyal nedeniyle sonlanıp sonlanmadığını anlayabilirsinizİşletim sistemi core dump’ı başka bir yere aktarırsa, gerektiğinde hemen hata ayıklayabilmek veya dağıtıma hata raporu gönderebilmek gibi avantajları da var
Linux çekirdeği core dump oluştururken kayıt konumunu belirlemek için
/proc/sys/kernel/core_patternadlı özel dosyayı okurDosyaya yazmak yerine bir programa pipe ile de aktarılabildiği için GUI iletişim kutusu gösterme, hata ayıklayıcıyı hemen çalıştırma, geliştiriciye raporu e-postayla gönderme gibi işlemler mümkün olur
systemd, çekirdeğin
core_patterndeğerini kendi yönettiği bir değere ayarlar; ancak systemd kullanmadan da aynı çekirdek özelliği kullanılabilirWindows XP geliştirilirken core dump’ların Microsoft’a gönderilmesi sayesinde varlığından bile haberdar olunmayacak birçok hatanın düzeltildiğine dair hikâyeler de var; Windows’a geliştirme araçları kurduğunuzda kendi programlarınızı geliştirirken isteğe bağlı hata ayıklayıcı oldukça işe yarar
Bu özellik 2003’te Linux’a eklendi; ayrıntılar
man 5 coreüzerinden görülebilirCore dump hata ayıklama için harikadır; ancak ilgisiz görünen dosyaların yanına konduğunda sıradan kullanıcıların kafasını karıştırır ve tanılama raporlama sistemi olarak kullanıldığında berbat olabilir
Gönderilen Windows çökme raporlarında ne kadar çok veri bulunduğunu ilk gördüğümde dehşete düşmüştüm
Kişisel verileri koruyan bir çökme raporlama sistemi varsayımıyla, gönderilen çökmeyi teşhis edebilmek için stack ve register bilgileriyle nedenini çıkarmayı öğrenmek gerekir
Bash’in betik içindeki komutları zaman zaman doğrudan
execettiğini hiç bilmiyordum; şaşırtıcı bir özellikBash sürecinin kendi yükü de çok büyük değil ve gereken yerlerde alışkanlıkla
execkullandığım için biraz hatalı tasarlanmış bir özellik gibi geliyorYine de toplam çalıştırma sayıları bir araya getirildiğinde beklediğimden daha büyük bir fark yaratabileceğini düşünüyorum