Bagaimana cara memeriksa, batas mana yang terlampaui? (Proses dihentikan karena ulimit.)

11

Mari kita asumsikan proses berjalan di lingkungan ulimited:

(
ulimit  ... -v ... -t ... -x 0 ...
./program
)

Program dihentikan.

Mungkin ada banyak alasan: memori / waktu / batas file terlampaui; hanya segfault sederhana; atau bahkan penghentian normal dengan kode pengembalian 0.

Bagaimana cara memeriksa apa alasan penghentian program, tanpa memodifikasi program?

PS Maksud saya "ketika biner diberikan". Mungkin beberapa pembungkus (ptrace-ing dll) mungkin bisa membantu?

Grzegorz Wierzowiecki
sumber

Jawaban:

6

Secara umum, saya kira Anda tidak bisa. (Beberapa sistem operasi mungkin menyediakannya, tetapi saya tidak mengetahui yang saya tahu mendukung hal ini.)

Referensi dokumen untuk batas sumber daya: getrlimitdari POSIX 2008.

Ambil contoh batas CPU RLIMIT_CPU.

  • Jika proses melebihi batas lunak, itu akan dikirim a SIGXCPU
  • Jika prosesnya melebihi batas yang keras, prosesnya menjadi sederhana SIGKILL

Jika Anda dapat wait()mengikuti program Anda, Anda dapat mengetahui apakah program tersebut dibunuh oleh SIGXCPU. Tetapi Anda tidak dapat membedakan SIGKILLpengiriman yang dikirim untuk pelanggaran batas keras dari pembunuhan lama biasa dari luar. Terlebih lagi, jika program menangani XCPU, Anda bahkan tidak akan melihatnya dari luar.

Hal yang sama untuk RLIMIT_FSIZE. Anda dapat melihat SIGXFSZdari wait()statusnya jika program tidak menanganinya. Tetapi begitu batas ukuran file terlampaui, satu-satunya hal yang terjadi adalah I / O lebih lanjut yang mencoba menguji batas itu hanya akan diterima EFBIG- ini akan ditangani (atau tidak, sayangnya) oleh program secara internal. Jika program ini menangani SIGXFSZ, sama seperti di atas - Anda tidak akan mengetahuinya.

RLIMIT_NOFILE? Yah, Anda bahkan tidak mendapat sinyal. opendan teman-teman kembali EMFILEke program. Itu tidak terganggu, sehingga akan gagal (atau tidak) dengan cara apa pun yang dikodekan untuk gagal dalam situasi itu.

RLIMIT_STACK? Bagus SIGSEGV, tidak dapat dibedakan dari skor alasan lain untuk dikirim. (Kamu akan tahu bahwa itu yang membunuh prosesnya, dari waitstatus.)

RLIMIT_ASdan RLIMIT_DATAhanya akan membuat malloc()dan beberapa orang lain mulai gagal (atau menerima SIGSEGVjika batas AS terpukul saat mencoba memperluas tumpukan di Linux). Kecuali jika program ini ditulis dengan sangat baik, itu mungkin akan gagal secara acak pada saat itu.

Jadi singkatnya, secara umum, kegagalan tidak tampak berbeda dari alasan kematian proses lainnya, jadi Anda tidak bisa yakin, atau dapat ditangani sepenuhnya dari program dalam hal ini memutuskan apakah / kapan / bagaimana hasilnya, bukan Anda dari luar.

Yang terbaik yang dapat Anda lakukan sejauh yang saya tahu adalah menulis sedikit kode yang memotong program Anda, menunggu, dan:

  • periksa status keluar untuk mendeteksi SIGXCPUdan SIGXFSZ(AFAIK, sinyal-sinyal itu hanya akan dihasilkan oleh OS untuk masalah batas sumber daya). Bergantung pada kebutuhan Anda yang sebenarnya, Anda dapat mengasumsikan itu SIGKILLdan SIGSEGVjuga terkait dengan batas sumber daya, tetapi itu agak sulit.
  • lihat apa yang bisa Anda dapatkan dari getrusage(RUSAGE_CHILDREN,...)implementasi Anda untuk mendapatkan petunjuk tentang yang lain.

Fasilitas khusus OS mungkin ada untuk membantu di sini (mungkin hal-hal seperti ptracedi Linux, atau Solaris dtrace), atau mungkin teknik tipe debugger, tetapi itu akan lebih terikat dengan implementasi spesifik Anda.


(Aku berharap orang lain akan menjawab dengan hal ajaib yang sama sekali tidak kusadari.)

Tikar
sumber
Baik. Bagaimana dengan ketiganya saja: (Mem) melebihi batas memori, (Waktu) batas waktu, (Kesalahan) kesalahan lain? Saya tahu tentang membuat pembungkus malloctapi sayangnya itu tidak menyelesaikan masalah memori secara umum, karena secara umum ini tentang panggilan sistem brk(apakah saya benar?).
Grzegorz Wierzowiecki
1
Membungkus malloc tidak akan membantu jika Anda tidak mengontrol program. Jika Anda berbicara tentang hacks seperti LD_PRELOADing bahwa ini batas untuk Anda "tidak memodifikasi proses" kendala, dan itu akan membantu sedikit, tetapi tidak benar-benar - malloc, brk, sbrkdan mmapakan gagal dengan ENOMEM, persis seperti jika Anda benar-benar berada dalam situasi memori rendah (tetapi jauh di bawah batas memori). Batas waktu adalah RLIMIT_CPU, saya tidak tahu batas waktu jam dinding.
Mat
Terima kasih telah memastikan saya brk. Seperti yang saya lihat, persyaratan 'program tidak menangani sinyal X, Y, Z ...' akan menyelesaikan masalah SIGXCPU, SIGXFSZ, SIGSEGV, terima kasih kepada waitpid (Jika saya salah, perbaiki saya).
Grzegorz Wierzowiecki
1
SIGSEGV dapat dimunculkan dalam situasi yang bukan merupakan pelanggaran batas sumber daya (null pointer dereference menjadi hal paling umum yang memunculkannya) - Anda tidak dapat memastikan itu merupakan serangan ulimit yang menyebabkannya.
Mat
Terima kasih telah memastikan saya brk. Seperti yang saya lihat, persyaratan 'program tidak menangani sinyal X, Y, Z ...' akan menyelesaikan masalah SIGXCPU, SIGXFSZ, SIGSEGV, terima kasih kepada waitpid. Apakah saya benar?
Grzegorz Wierzowiecki
3

Saat ini saya sedang melakukan beberapa pekerjaan pada masalah yang sama. Saya sudah dapat memiliki solusi parsial untuk itu. Saya telah menggunakan susbsystem audit . Anda dapat melacak pekerjaan di [1].

[1] https://github.com/PaulDaviesC/Logging-limits.conf

PaulDaviesC
sumber