Ke mana perginya galat segmentasi saya?
(rmpr.xyz)- Saat program C dikompilasi dan dijalankan berulang dengan
entr,hellomemang berhenti secara abnormal, tetapi pesanSegmentation faulttidak 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 -cditulis secara eksplisit, bila pada praktiknya hanya ada satu perintah tersisa, Bash dapat mengganti dirinya sendiri denganexecvetanpa membuat proses baru, sehingga shell induk yang seharusnya mencetak pesan itu pun hilang - Dalam skrip terpisah, Bash yang dimulai lewat shebang menjalankan
./hellosebagai anak dan menunggunya, sehingga ia dapat mendeteksiSIGSEGVdan mencetakSegmentation fault (core dumped) - Menjalankan
./hellodi dalam subshell(./hello)atau menambahkan; truedi belakangnya agar masih ada pekerjaan lanjutan dapat mencegah optimisasiexecdan membuat pesan galat kembali terlihat
Jalur eksekusi tempat pesannya menghilang
-
Dengan perintah
entrberikut, kompilasi dan eksekusi diulang setiap kalihello.cberubahls hello.c | entr -s "gcc -o hello hello.c && ./hello" -
Meski
helloberakhir karena galat segmentasi, tidak ada output apa pun yang tersisa, tanpa pesanSegmentation faultmaupun status keluar non-zero yang terlihat -
Hasilnya tetap sama meskipun perintah dibungkus dengan
bash -cls hello.c | entr -s "bash -c 'gcc -o hello hello.c && ./hello'" -
Sebaliknya, jika perintah yang sama dipindahkan ke
run.shlalu dijalankan, galatnya terlihat#!/bin/bash gcc -o hello hello.c && ./hellols 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
SIGSEGVsebelum 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 lewatexecve - Dalam sebagian besar eksekusi, optimisasi ini tidak tampak dari luar
- Pada pendekatan skrip,
entrmenjalankan./run.shsebagai anak, dan shebang memulai Bash baru - Bash baru itu kemudian menjalankan
gcc, lalu melakukan fork untuk./hellodan menunggunya, sehingga bisa mendeteksi bahwa anak berakhir karenaSIGSEGVdan meninggalkan pesan galat
- Program yang crash sebenarnya sudah selesai, dan shell induk memungut proses anak lalu memastikan bahwa anak itu mati karena
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
./hellodijalankan di subshell hasil fork - Karena Bash tetap mempertahankan peran sebagai induk, ia bisa memungut akhir
SIGSEGVdari subshell dan mencetak pesannya
- Tanda kurung memaksa
- Menyisakan pekerjaan setelah perintah yang crash juga dapat mencegah optimisasi
execls 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./helloselesai, sehingga ia tidak mengganti dirinya sendiri dengan program tersebut - Dengan begitu, pesan galat segmentasi bisa dikonfirmasi tanpa skrip pembungkus terpisah
- Karena ada
1 komentar
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 tempatAkan 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
coredumpctlbisa digunakan untuk menampilkan dan mengambil core dump terbaruSelain 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-bacaBukankah direktori kerja jauh lebih baik sebagai lokasi default?
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 sinyalJika 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_patternuntuk menentukan lokasi penyimpanannyaAlih-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_patternmilik kernel ke nilai yang dikelolanya sendiri, tetapi fitur kernel yang sama tetap bisa digunakan meski tidak memakai systemdAda 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 coreCore 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
execpada perintah di dalam skrip, dan itu fitur yang mengejutkanBeban proses Bash sendiri juga tidak besar, dan di tempat yang diperlukan saya biasanya memakai
execkarena kebiasaan, jadi fitur ini terasa seperti desain yang agak keliruNamun jika total jumlah eksekusinya dijumlahkan, mungkin saja dampaknya lebih besar daripada yang saya duga