1 poin oleh GN⁺ 4 jam lalu | 1 komentar | Bagikan ke WhatsApp
  • Saat program C dikompilasi dan dijalankan berulang dengan entr, hello memang berhenti secara abnormal, tetapi pesan Segmentation fault tidak muncul setelah output kompilasi
  • Pesan ini tidak dicetak oleh program yang crash, melainkan oleh shell induk yang memungut proses anak dan memastikan bahwa proses itu berakhir karena SIGSEGV
  • Bahkan jika bash -c ditulis secara eksplisit, bila pada praktiknya hanya ada satu perintah tersisa, Bash dapat mengganti dirinya sendiri dengan execve tanpa membuat proses baru, sehingga shell induk yang seharusnya mencetak pesan itu pun hilang
  • Dalam skrip terpisah, Bash yang dimulai lewat shebang menjalankan ./hello sebagai anak dan menunggunya, sehingga ia dapat mendeteksi SIGSEGV dan mencetak Segmentation fault (core dumped)
  • Menjalankan ./hello di dalam subshell (./hello) atau menambahkan ; true di belakangnya agar masih ada pekerjaan lanjutan dapat mencegah optimisasi exec dan membuat pesan galat kembali terlihat

Jalur eksekusi tempat pesannya menghilang

  • Dengan perintah entr berikut, kompilasi dan eksekusi diulang setiap kali hello.c berubah

    ls hello.c | entr -s "gcc -o hello hello.c && ./hello"
    
  • Meski hello berakhir karena galat segmentasi, tidak ada output apa pun yang tersisa, tanpa pesan Segmentation fault maupun status keluar non-zero yang terlihat

  • Hasilnya tetap sama meskipun perintah dibungkus dengan bash -c

    ls hello.c | entr -s "bash -c 'gcc -o hello hello.c && ./hello'"
    
  • Sebaliknya, jika perintah yang sama dipindahkan ke run.sh lalu dijalankan, galatnya terlihat

    #!/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
    
  • Siapa yang mencetak Segmentation fault

    • Program yang crash sebenarnya sudah selesai, dan shell induk memungut proses anak lalu memastikan bahwa anak itu mati karena SIGSEGV sebelum mencetak pesan tersebut
    • Karena itu, jika tidak ada shell induk yang tersisa untuk mencetak pesan, tidak akan muncul apa pun
    • Dalam bash -c "some_command", jika pada dasarnya Bash hanya perlu menjalankan perintah itu saja, Bash dapat tidak melakukan fork dan malah mengganti dirinya sendiri lewat execve
    • Dalam sebagian besar eksekusi, optimisasi ini tidak tampak dari luar
    • Pada pendekatan skrip, entr menjalankan ./run.sh sebagai anak, dan shebang memulai Bash baru
    • Bash baru itu kemudian menjalankan gcc, lalu melakukan fork untuk ./hello dan menunggunya, sehingga bisa mendeteksi bahwa anak berakhir karena SIGSEGV dan meninggalkan pesan galat

Dua cara untuk mempertahankan shell induk

  • Jika perintah yang crash dijalankan di dalam subshell, pesannya akan muncul lagi
    ls hello.c | entr -s "gcc -o hello hello.c && (./hello)"
    hello.c: line 1: 106595 Segmentation fault (core dumped) ( ./hello )
    
    • Tanda kurung memaksa ./hello dijalankan di subshell hasil fork
    • Karena Bash tetap mempertahankan peran sebagai induk, ia bisa memungut akhir SIGSEGV dari subshell dan mencetak pesannya
  • Menyisakan pekerjaan setelah perintah yang crash juga dapat mencegah optimisasi exec
    ls hello.c | entr -s "bash -c 'gcc -o hello hello.c && ./hello; true'"
    bash: line 1: 109516 Segmentation fault (core dumped) ./hello
    
    • Karena ada ; true, Bash masih punya pekerjaan setelah ./hello selesai, sehingga ia tidak mengganti dirinya sendiri dengan program tersebut
    • Dengan begitu, pesan galat segmentasi bisa dikonfirmasi tanpa skrip pembungkus terpisah

1 komentar

 
GN⁺ 4 jam lalu
Komentar di Lobste.rs
  • Distribusi Linux modern sering merepotkan karena secara default menonaktifkan core dump
    Core dump bisa diaktifkan lagi dengan ulimit -c unlimited, tetapi berkas core tampaknya juga tidak dibuat di direktori yang sama dengan berkas executable, dan sepertinya systemd memindahkannya ke suatu tempat
    Akan bagus kalau core dump diaktifkan secara default dan diletakkan di direktori yang sama dengan executable seperti di OpenBSD, tetapi sekarang saat terjadi crash biasanya executable harus dijalankan ulang di dalam gdb

    • Di systemd, coredumpctl bisa digunakan untuk menampilkan dan mengambil core dump terbaru
    • Menaruh core dump di lokasi executable berada tampak seperti pilihan yang cukup aneh
      Selain tidak terpikir untuk mencari core dump di tempat seperti /usr/bin, lokasi semacam itu juga sering berada di sistem berkas yang kapasitasnya kecil atau hanya-baca
      Bukankah direktori kerja jauh lebih baik sebagai lokasi default?
    • Alasan berkas core dinonaktifkan secara default tampaknya karena para pakar keamanan menganggap pengguna tidak bisa menjalankan Linux dengan aman, dan berkas core yang dibiarkan begitu saja bisa dieksploitasi
      Bahkan ketika pengguna mengaktifkan berkas core, rasanya mereka dianggap tidak tahu apa yang mereka lakukan, sehingga berkas itu disembunyikan di tempat yang bahkan sulit ditemukan oleh root
  • Jika menulis program dengan C, D, dan sejenisnya lalu ingin tahu penyebab penghentiannya, cukup periksa nilai balik dari system call wait, dan Anda bisa mengetahui apakah program berakhir karena sinyal
    Jika sistem operasi meneruskan core dump ke tempat lain, ada juga keuntungan bahwa Anda bisa langsung men-debug saat diperlukan atau mengirim laporan kesalahan ke distribusi
    Saat membuat core dump, kernel Linux membaca berkas khusus bernama /proc/sys/kernel/core_pattern untuk menentukan lokasi penyimpanannya
    Alih-alih menuliskannya sebagai berkas, core dump juga bisa diteruskan lewat pipe ke program, sehingga memungkinkan penanganan seperti menampilkan dialog GUI, langsung menjalankan debugger, atau mengirim laporan lewat email ke pengembang
    systemd menetapkan core_pattern milik kernel ke nilai yang dikelolanya sendiri, tetapi fitur kernel yang sama tetap bisa digunakan meski tidak memakai systemd
    Ada juga cerita bahwa pada masa pengembangan Windows XP, core dump dikirim ke Microsoft sehingga mereka memperbaiki berbagai bug yang mungkin bahkan tidak mereka ketahui keberadaannya; dan jika memasang alat pengembangan di Windows, debugger on-demand cukup berguna saat mengembangkan program sendiri
    Fitur ini diperkenalkan ke Linux pada 2003, dan detailnya bisa dilihat di man 5 core

  • Core dump sangat bagus untuk debugging, tetapi jika diletakkan di samping berkas yang tampak tidak berkaitan, hal itu membingungkan pengguna umum, dan bisa sangat buruk jika dipakai sebagai sistem pelaporan diagnostik
    Saya terkejut saat pertama kali melihat seberapa banyak data yang masuk dalam laporan crash Windows yang dikirimkan
    Dengan asumsi ada sistem pelaporan crash yang melindungi privasi, kita perlu belajar menyimpulkan penyebab hanya dari informasi stack dan register agar crash yang dikirimkan bisa didiagnosis

  • Saya sama sekali tidak tahu bahwa Bash kadang-kadang langsung melakukan exec pada perintah di dalam skrip, dan itu fitur yang mengejutkan
    Beban proses Bash sendiri juga tidak besar, dan di tempat yang diperlukan saya biasanya memakai exec karena kebiasaan, jadi fitur ini terasa seperti desain yang agak keliru
    Namun jika total jumlah eksekusinya dijumlahkan, mungkin saja dampaknya lebih besar daripada yang saya duga