1 puan yazan GN⁺ 4 시간 전 | 1 yorum | WhatsApp'ta paylaş
  • entr ile bir C programını tekrar tekrar derleyip çalıştırınca hello anormal biçimde sonlandı, ancak derleme çıktısından sonra Segmentation fault mesajı görünmedi
  • Bu mesajı çöken program değil, alt süreci toplarken SIGSEGV ile sonlandığını gören üst kabuk yazdırır
  • bash -c açıkça belirtilse bile geriye kalan komut fiilen tek bir komutsa Bash yeni bir süreç oluşturmadan execve ile 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çin SIGSEGVi görür ve Segmentation fault (core dumped) çıktısını verir
  • ./helloyu alt kabukta (./hello) çalıştırmak veya arkasına ; true ekleyerek sonraki işi bırakmak, exec optimizasyonunu engelleyip hata mesajını görmeyi sağlar

Mesajın kaybolduğu çalıştırma yolu

  • Aşağıdaki entr komutuyla hello.c her değiştiğinde derleme ve çalıştırma tekrarlanır

    ls hello.c | entr -s "gcc -o hello hello.c && ./hello"
    
  • hello segmentation fault ile sonlandı, ancak Segmentation fault mesajı ya da gözle görülür sıfır olmayan bir çıkış durumu olmadan hiçbir çıktı bırakmadı

  • Komutu bash -c ile 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.sh içine taşınıp çalıştırıldığında hata gösterilir

    #!/bin/bash
    gcc -o hello hello.c && ./hello
    
    ls 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 SIGSEGV ile ö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 etmeden execve ile 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ürecin SIGSEGV ile sonlandığını görerek hata mesajı bırakabilir

Ü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 SIGSEGV ile sonlanmasını toplayıp mesajı yazdırabilir
  • Çöken komuttan sonra çalıştırılacak bir iş bırakmak da exec optimizasyonunu engelleyebilir
    ls hello.c | entr -s "bash -c 'gcc -o hello hello.c && ./hello; true'"
    bash: line 1: 109516 Segmentation fault (core dumped) ./hello
    
    • ; true nedeniyle Bash, ./hello bittikten 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

 
GN⁺ 4 시간 전
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 unlimited ile 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üyor
    OpenBSD’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

    • systemd’de son core dump’ları listelemek ve almak için coredumpctl kullanılabiliyor
    • Core dump’ı çalıştırılabilir dosyanın bulunduğu yere koymak epey tuhaf bir tercih gibi görünüyor
      /usr/bin gibi yerlerde core dump aramayı düşünmem bile; üstelik bu tür konumlar çoğu zaman kapasitesi küçük ya da salt okunur dosya sistemlerinde bulunuyor
      Varsayılan konum olarak çalışma dizini çok daha iyi olmaz mı?
    • Core dosyalarının varsayılan olarak devre dışı olmasının nedeni, güvenlik uzmanlarının kullanıcıların Linux’u güvenli biçimde işletemeyeceğini ve ortada bırakılmış core dosyalarının kötüye kullanılabileceğini düşünmesi gibi görünüyor
      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 wait sistem ç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_pattern adlı özel dosyayı okur
    Dosyaya 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_pattern değerini kendi yönettiği bir değere ayarlar; ancak systemd kullanmadan da aynı çekirdek özelliği kullanılabilir
    Windows 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ülebilir

  • Core 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 exec ettiğini hiç bilmiyordum; şaşırtıcı bir özellik
    Bash sürecinin kendi yükü de çok büyük değil ve gereken yerlerde alışkanlıkla exec kullandığım için biraz hatalı tasarlanmış bir özellik gibi geliyor
    Yine de toplam çalıştırma sayıları bir araya getirildiğinde beklediğimden daha büyük bir fark yaratabileceğini düşünüyorum